View previous topic :: View next topic 
Author 
Message 
bland
Joined: 27 Oct 2004 Posts: 3

Posted: Mon Feb 07, 2005 11:33 am Post subject: real*8 resolution not correct 


To start, I attempted to search for an answer to this but am not quite sure what to search for.
I have a test program:
Code: 
program realtest
real*8 V1, V2, V3
integer*4 i
V1 = 1.0d0
V2 = 0.1d0
V3 = 0.0d0
do i = 1,50
V3 = V1+V2
write(*,77) V3
77 FORMAT(F35.30)
V1 = V3
enddo
end

V1 and V2 have the proper values, with 0's filled in. However after the 6th iteration my V3 = 1.600000000000001 and the resolution continues to fluctuate for the values after that. Is there a way to specifiy the 'd0' in the V3=V2+V1 statement or am I doing something wrong like in my other posting on real*8's? Thanks for helping me understand this better. 

Back to top 


mkcolg
Joined: 30 Jun 2004 Posts: 6745 Location: The Portland Group Inc.

Posted: Mon Feb 07, 2005 3:33 pm Post subject: 


Hi bland,
What's happening here is not a Fortran specific issue. Rather, most binary real numbers can not represent exactly their decimal equivlent. Think about what the decimal equivlent of the fraction 1/3 is, .333333333.... The fraction 1/3 can not be represented exactly as a decimal so in every day life we always use an approximate value.
With the binary representation of real values, the decimal "0.1" can not be represented exactly. Instead, an approximation "0.10000000000000001" is used instead (the exact approximation will vary by system). As you add more and more values together, the error introduced by the approximation will grow.
There is a lot on the web about this issue, so doing a web search for "binary real number representation" might help.
 Mat 

Back to top 


bland
Joined: 27 Oct 2004 Posts: 3

Posted: Wed Feb 09, 2005 8:24 am Post subject: 


I understand what you wrote, but I don't understand how adding 1.0d0 + 0.1d0 can some how yeild 1.100000000000000100000000000. This crashes any loop we try to create that is dependent on the output as shown in my test case. We are trying to see if something is equal to 1.5d0 (for example) but the output never equals that exactly.
Is there a way to fill in the rest of the output values with zeros as we do with the d0 on the constants? I definitely see these resolution differences between Linux, Tru64, and VMS all of which have different "epsilons." How would you work around something like this?
Thanks for the help. 

Back to top 


mkcolg
Joined: 30 Jun 2004 Posts: 6745 Location: The Portland Group Inc.

Posted: Wed Feb 09, 2005 4:44 pm Post subject: 


Hi Bland,
Since 0.1 has an infinite binary expansion, even in double precision (ie 0.1d0) it can not be represented as an exact binary number. Adding the extra " .0000000000000001" is the closest your hardware can come to it. Other hardware might get closer, but will never be exact.
The best way to think about a REAL value is that it is an approximation and thus always wrong. It just a matter of how wrong. Granted some values can be represented, but think of these as the exception not the rule. As such, a REAL should not be used to detemine if something is equal.
One way around this is to account for the error and test if the sum is within a specified delta. Don't test for an exact match, just check if the value is within a range.
Another option if you are only using larger fractional amounts, such as .1, is to scale your value and use a INTEGER instead. An INTEGER can be used to check for equilvance. For example, if your summing U.S. dollars, instead of summing the dollars and cents, simply sum the cents. In other words, scale everything by 100 and use intergers in place of your reals. If you need more precision, simply scale by a larger amount.
Hope this helps,
Mat 

Back to top 




You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum

Powered by phpBB © phpBB Group
