0

To find the difference between two values, I used the command below

awk -v n1="1581097198.000749862" -v n2="1581097198.000449861" 'BEGIN{printf ("%.9f\n",n1-n2)}'

Output I get using the above command: 0.000299931

But it is wrong, the correct value is .000300001.

Am I doing anything wrong?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • 4
    Most likely, the only thing your'e doing wrong is expecting perfect accuracy in floating point arithmetic. – William Pursell Jun 06 '21 at 21:24
  • 4
    The canonical for that is [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – tripleee Jun 06 '21 at 22:19

2 Answers2

3

Using the wrong tool for the job.

echo "1581097198.000749862 - 1581097198.000449861" | bc -l
.000300001

If you want to modify the formatting you can always pipe the output from bc through awk.

tink
  • 14,342
  • 4
  • 46
  • 50
  • 2
    ...because all numbers in `awk` are floating point and so affected by floating point math considerations while `bc` never uses floating point but uses fixed precision decimal numbers instead. – Ed Morton Jun 07 '21 at 14:27
1

bc is absolutely a great tool for this job. It is automatically arbitrary precision and the gotchas with floating point are avoided.

There are a couple of alternates to bc to consider.

You can use GNU awk if it was compiled with the MPFR library. You need to set the precision to something more than the default 53 bits. In this case, quad precision or 128 bits is fine:

n1="1581097198.000749862"
n2="1581097198.000449861"  

gawk -M -v PREC='quad' -v n1="$n1" -v n2="$n2" 'BEGIN{printf ("%.10f\n",n1-n2)}'
0.0003000010

The advantage with gawk is it is likely faster with a fixed word size floating point vs most arbitrary precision methods. They can be orders of magnitude slower.

You can also use perl with bignum:

echo "$n1 $n2" | perl -Mbignum -lanE 'say $F[0]+0.0 - $F[1]'
0.000300001

(The $F[0]+0.0 just tells Perl to treat $F[0] as number which then triggers the conversion to a bignum)

dawg
  • 98,345
  • 23
  • 131
  • 206