Discussion:
inconsistent for() and while() behavior when using floating point
(too old to reply)
Yuri Pankov
2018-01-15 14:38:54 UTC
Permalink
Hi,

Looking at https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217149, I
noticed that it isn't a seq(1) problem per se, rather for() and while()
loops behaving inconsistently while using floating point, i.e.:

double i;

for (i = 1; i <= 2.00; i += 0.1)
printf("%g\n", i);

would produce:

1
...
1.9

but:

double i;

for (i = 1; i <= 2; i += 0.2)
printf("%g\n", i);

would correctly end with 2:

1
...
2

$ cc -v
FreeBSD clang version 6.0.0 (branches/release_60 321788) (based on LLVM
6.0.0)
Target: x86_64-unknown-freebsd12.0
Thread model: posix
InstalledDir: /usr/bin

though gcc 4.4.4 on illumos behaves the same.

Is this a known problem with loops and floating point numbers?
Hans Petter Selasky
2018-01-15 14:45:51 UTC
Permalink
Post by Yuri Pankov
Hi,
Looking at https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217149, I
noticed that it isn't a seq(1) problem per se, rather for() and while()
        double i;
        for (i = 1; i <= 2.00; i += 0.1)
                printf("%g\n", i);
        1
        ...
        1.9
        double i;
        for (i = 1; i <= 2; i += 0.2)
                printf("%g\n", i);
        1
        ...
        2
Hi,

The decimal value "0.2" is the same like the fraction "1/5", which
cannot be represented by a float nor double without rounding error. The
more times you iterate the bigger the error becomes.

When you compare an integer with a float rounding happens. Check this out:

if ((int)(float)0.999999999999999999999 >= (int)1)
printf("OK\n");

Sequences using floating point should technically only use steps which
can be written like this: "remainder * pow(2, -shift)".

--HPS
Hans Petter Selasky
2018-01-15 14:49:47 UTC
Permalink
Hi,

The "seq" utility should use two 64-bit integers to represent the
10-base decimal number instead of float/double. And then you need to
step this pair of integers.

--HPS
David Chisnall
2018-01-15 14:54:59 UTC
Permalink
The "seq" utility should use two 64-bit integers to represent the 10-base decimal number instead of float/double. And then you need to step this pair of integers.
Sometimes, people think 'I have a problem and I will solve it with floating point values' and then they have 1.99999999 problems.
David
Yuri Pankov
2018-01-15 15:54:54 UTC
Permalink
The "seq" utility should use two 64-bit integers to represent the 10-base decimal number instead of float/double. And then you need to step this pair of integers.
Thanks for the hint!
Sometimes, people think 'I have a problem and I will solve it with floating point values' and then they have 1.99999999 problems.
Well, seq(1) is about floating numbers, so at least initially using them
internally would seem correct, though reading your replies I now
understand it's not :-)
Warner Losh
2018-01-15 15:52:54 UTC
Permalink
Post by Yuri Pankov
Is this a known problem with loops and floating point numbers?
Yes. Many exact fractions in base-10 aren't exact in base-2, so you get
accumulation of errors based on the tiny difference and see behavior like
this. This is totally expected. You have to work around the problem using a
computation method that doesn't accumulate errors.

Warner
Mehmet Erol Sanliturk
2018-01-15 17:38:15 UTC
Permalink
Post by Yuri Pankov
Hi,
Looking at https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217149, I
noticed that it isn't a seq(1) problem per se, rather for() and while()
double i;
for (i = 1; i <= 2.00; i += 0.1)
printf("%g\n", i);
1
...
1.9
double i;
for (i = 1; i <= 2; i += 0.2)
printf("%g\n", i);
1
...
2
$ cc -v
FreeBSD clang version 6.0.0 (branches/release_60 321788) (based on LLVM
6.0.0)
Target: x86_64-unknown-freebsd12.0
Thread model: posix
InstalledDir: /usr/bin
though gcc 4.4.4 on illumos behaves the same.
Is this a known problem with loops and floating point numbers?
_______________________________________________
When you perform floating point computations , it may be useful to remember
that , the last bits of floating point numbers may be considered to be
"noise" .
For that reason , the same "for" or "while" loops may behave differently in
different times and places .

To make floating point related loops more deterministic , the useful steps
may be to compute "step size" and "number of steps" , and use integer
variables for counting loop steps with multiplication of "loop counter"
and "step size" during loop steps : For floating point loop counter T =
"integer loop counter" * "step size" .
A statement like T = T + "step size" will/may produce wrong results if
number of steps is sufficiently large .


Computer arithmetic and theoretical arithmetic are not the same .
For example , addition is not associative in computer arithmetic : a + ( b
+ c ) is not always equal to ( a + b ) + c .



Mehmet Erol Sanliturk
Steve Kargl
2018-01-15 17:55:04 UTC
Permalink
Post by Mehmet Erol Sanliturk
When you perform floating point computations , it may be useful
to ...
read David Goldberg's paper, "What Every Computer Scientist Should
Know about Floating-Point Arithmetic."

http://www.validlab.com/
--
Steve
Loading...