Why does floating-point operations differ from the intended result?

Asked 2 years ago, Updated 2 years ago, 31 views

I have a question about missing information.

Please tell me why 1/n is added n times in the program below, but the answer is not 1.0.

 float f=0.0; 
int n = 100000;

for(inti=0;i<n;i++){ 
    f+ = 1.0/n;
}

println("f="+f);

java

2022-09-30 19:27

5 Answers

Strictly speaking makes it difficult, so including parables

The number that can be accurately expressed in decimal notation but not in binary notation (1/100000 is exactly this) is a circular decimal in binary notation.Your computer's memory is finite, so you can't handle infinite digits, so you need to stop somewhere appropriate.There will always be an error with the true value.This is called a termination error.

For example, 1/3 can be represented correctly by "trivial notation," while 0.33333 is equivalent to "decimal notation equals circular decimal." The number terminated by 0.33333 is not exactly 1/3Discontinued results in a difference from the true value.

Now, consider adding this (1/3 or 0.33333).

If 1/3+1/3+1/3 is expressed in trimester, 0.1+0.1+1, you get 1 and you get the exact result (although no computer has a float like that).

The decimal notation 0.33333+0.33333+0.33333 will result in 0.9999.Therefore, if only the termination error accumulates, the sum of the positive numbers will always be less than the true value.

When dealing with this kind of floating-point number inside the computer, a rounding error occurs separately from the termination error.Rounding error occurs when the number that cannot be expressed correctly is replaced by the number that can be expressed correctly internally.The previous 1/3 terminated with 0.33333 because 0.3333.... infinite digits cannot be represented.In , whether 2/3 is 0.66666 or 0.66667 depends on the case and request.Rounding to a lower error value may be greater than the original value.

The example presented is "cut off and become smaller."It happens to be bigger as a result of both "rolling and growing".

でこの制御ができるかどうか知らんので のサンプル MSVC だと、この辺の「丸め方向」を _controlfp() で制御できます。these days in order to end < code > _ < / code > to use a dot I found < / >

#include<stdio.h>
# include <float.h>
int main() {
    unsigned intfp;
    _controlfp_s(&fp,0,0);
    _controlfp_s(&fp,_RC_CHOP,_MCW_RC);
    float f = 0.0;
    int n = 100000;

    for(inti=0;i<n;i++){
        f+ = 1.0/n;
    }

    printf("f=%g\n",f);
}

In the example above, _RC_CHOP is "rounded in the 0 direction" (rounded to a recent value with a lower absolute value), but the result is 0.997263, where _RC_NEAR is "rounded to the nearest value" (standard setting), and the result is 1.00099.If you try various things like n=104857 or _RC_UP or _RC_DOWN in the answer/comment, you will understand better.


2022-09-30 19:27

Floating-point numbers are approximate, and 1.0/100000 does not exactly represent 0.000001 and contains errors.
Running f+=1.0/n; 100000 times also amplifies the error by 100000 times.Therefore, f is not 1.0.


2022-09-30 19:27

Termination error
an error caused by discontinuing an infinite decimal calculation in the middle

(omitted)

Missing information
in floating-point operations, an error in which some or all of the effective digits of a small number of absolute values are not reflected in the result when adding and subtracting large numbers of absolute values and small numbers of absolute values

The code in the question statement is not due to "information loss", but "stop error".

The decimal representation 1/100000(0.00001) is a finite decimal, but is expressed in binary in the program, which is an infinite decimal (0.000000000000001010011111000101101011000100011000110100011000110001000110001...).
This results in a termination error.

Note:


2022-09-30 19:27

"I think it's the ""information missing"" of the questioner."

https://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html

Floating point has a "rounding error" to represent 23 bits of a valid binary digit when the infinite decimal is float.

Termination error
 an error caused by discontinuing an infinite decimal calculation in the middle

Missing digits
 By subtracting two numbers whose values are close to each other, the effective number of digits decreases

Missing information
 If the absolute value is added to the larger value, the smaller value will lose the information it has.

and so on.

The problem with this calculation is
when adding 1/100000 Since the float type has approximately 6 digits of accuracy, the number of additional digits and the number of valid digits added gradually differ
"Because of this, ""information loss"" occurs."

1/100000 is about 0.0000099999747 (6 valid digits), so

For the first addition,

 0.0000099999747 (6 valid digits)
+ 0.0000099999747 (6 valid digits)

While the number of valid digits is close, there will be no missing information when adding six valid digits to each other, as shown in

As the calculation progresses

 0.12345678 (6 valid digits)
+ 0.0000099999747 (6 valid digits)


because the decimal position of the addition and the additional number is deviated as shown in Only one or two valid digits will be used for the number of additional digits.
"This is ""lost information"" and the error in addition is gradually increasing."


when viewing the program The first one was an addition of 6 valid digits plus 6 valid digits, but
Ah, as f approaches 1,
It's an addition of 6 valid digits plus 2 valid digits...
It doesn't look accurate.
Is the final valid digit about 3 digits?
If you want the final calculation to be 6 significant digits, the middle calculation will be double and 15 significant digits
I have to calculate...
I think we can decide that

What is the reason why the answer is not 1.0 when the program adds 1/n times n times?

There is an error due to rounding error in the calculation of floating point
In this calculation method, the following missing information accumulates, resulting in a larger error.

Effective accuracy: Add 6 digits 10 times
Effective accuracy: Add 5 digits 90 times
US>Effective accuracy: 900 additional 4 digits

Effective accuracy 3-digit addition 9000 times
Effective accuracy Add two digits 90,000 times
Therefore, the final valid number of digits in the total calculation should be between 2 and 3 digits.

1.000990152 in the calculation results is within the valid digits of 1.0, so
This is the expected result of this calculation.


2022-09-30 19:27

1.0/100000 is expressed as float to 9.9999747e-06 in decimal. Less than the exact value.
However, the result of adding 1.0/100000 100000 times is 1.000990152e+00 and
It is greater than the exact value.
Therefore, rounding error alone when 1.0/100000 is expressed as float is not enough.

In order to explain the reason, I will try to add it to a large number.
1.0/100000 is expressed as float to 1.010011111000101101100 x 2^-17 .
Add this to 0.5 (1.0000000000000000000000000 x 2^-1 on float).

First of all, add the digits together

 0.00000000000000000101001111100010110101100 x 2^-1
1.000000000000000000000000000 x 2^-1

Add them together

1.00000000000000000101001111100010110101100 x 2^-1

Round to even under the valid float digits (23 decimal places) (in this case, the same result as rounding).

1.0000000000000000010101000 x 2^-1

In this case, you will find that rounding up occurs.

Now, if the number is between 0.5 and less than 1.0, the float will be 1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2^-1.
If you add 1.0/100000 to
because there are no decimal places and fewer than 23 digits. Any number less than 23 decimal places is equal to 1.0/100000.
In other words, you can see that the result of the addition is always rounded up, just like the addition with 0.5.
(Strictly speaking, if the result is 1.0 or higher, it will be rounded up or not, but the impact will be minimal as it only occurs once during the loop addition.)


Because almost all of the addition to 1.0/100000 in the loop are rounded up,
I think you can understand that the results are biased toward the larger ones.


2022-09-30 19:27

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.