sanjay
sanjay

Reputation: 755

awk floating point comparison not working

I have input file with with x1 , x2 and x values, I want to check if x is midpoint between x1 and x2. But the comparison is failing.

sample input file

x1=20.9280 x2=20.9600 x=20.9440
x1=20.9280 x2=20.9600 x=20.9440
x1=22.7840 x2=22.8160 x=22.8000

Awk command

awk -F'[ =]' '{ if(($2 + $4)/2 != ($6)) print ($2 + $4)/2, " ", $6;}' sample

OUTPUT

20.944   20.9440
20.944   20.9440
22.8   22.8000

Comparison is failing due to extra zeros after decimal points. Please help to fix it.

Upvotes: 1

Views: 1104

Answers (3)

Ed Morton
Ed Morton

Reputation: 203985

As others have pointed out, if you are having a problem then it's probably that you're just tripping over the common floating point arithmetic issue but since all of your input values have the same precision you can just get rid of the .s to treat the input numbers as integers and multiply by 2 instead of dividing by 2 just to keep it an integer comparison too:

$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) == ($2+$4){$0=o; print ($2+$4)/2, $6}' file
20.944 20.9440
20.944 20.9440
22.8 22.8000

$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) != ($2+$4){$0=o; print ($2+$4)/2, $6}' file
$

Upvotes: 0

anubhava
anubhava

Reputation: 785491

This is happening due to floating point comparison issue commonly found in all platforms.

You may use this awk for floating point number comparison by converting number to a floating point with 4 decimal points:

awk -F'[ =]+' '{avg = sprintf("%.4f", ($2 + $4) / 2)} avg != $6 { print avg, $6 }' file

If you have gnu awk then you can set precision to a lower number:

awk -M -v PREC=30 -F'[ =]+' '{avg = ($2 + $4) / 2; $6 += 0} avg != $6 { print avg, $6 }' file

Upvotes: 1

James Brown
James Brown

Reputation: 37424

Not really an anwser but do demonstrate. You are comparing floating point numbers, they are not equal. I replaced print with printf and modifiers with enough decimals (20, %.20f):

$ awk -F'[ =]' '{
    if(($2 + $4)/2 != ($6)) 
        printf "%.20f %.20f\n", ($2 + $4)/2, $6
}' file

Ottput:

20.94400000000000261480 20.94399999999999906208
20.94400000000000261480 20.94399999999999906208
22.79999999999999715783 22.80000000000000071054

So use sprintf and appropriate modifiers (see the printf I used) to control the values.

Upvotes: 1

Related Questions