I can think of two ways to do this. First, just write the query like this:
select s.id,
case when (f1(s.col1) <> t.t-col1) then 'col 1 error' else '' end as col1_status,
case when (f2(s.col2) <> t.t-col2) then 'col 2 error' else '' end as col2_status,
case when (f3(s.col3) <> t.t-col3) then 'col 3 error' else '' end as col3_status
from source as s
inner join target as t on (s.id = t.id)
where f1(s.col1) <> t.t-col1 or f2(s.col2) <> t.t-col2 or f3(s.col3) <> t.t-col3
Yes it can be bulky if the functions are complex, but it gets the job done.
The other way is to create a view on the source table to look like the target table using the transform functions:
create view source_transformed as select id,f1(col1) as t_col1,f2(col2) as t_col2,f3(col3) as t_col3 from source
Then your query gets simple:
select s.id,
case when (s.t_col1 <> t.t-col1) then 'col 1 error' else '' end as col1_status,
case when (s.t_col2 <> t.t-col2) then 'col 2 error' else '' end as col2_status,
case when (s.t_col3 <> t.t-col3) then 'col 3 error' else '' end as col3_status
from source_transformed as s
inner join target as t on (s.id = t.id)
where s.t_col1 <> t.t-col1 or s.t_col2 <> t.t-col2 or s.t_col3 <> t.t-col3
HTH
Andy