www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Funny issue with casting double to ulong

reply Saurabh Das <saurabh.das gmail.com> writes:
Consider this snippet:

void main()
{
     import std.stdio;
     auto a = 6.2151;
     auto b = a * 10000;
     auto c = cast(ulong)b;
     writeln("a: ", typeof(a).stringof, " ", a);
     writeln("b: ", typeof(b).stringof, " ", b);
     writeln("c: ", typeof(c).stringof, " ", c);

     auto x = 62151.0;
     auto y = cast(ulong)x;
     writeln("x: ", typeof(x).stringof, " ", x);
     writeln("y: ", typeof(y).stringof, " ", y);
}

The output is:
a: double 6.2151
b: double 62151
c: ulong 62150
x: double 62151
y: ulong 62151

Why does c round off from 62151 to 62150 when casting to ulong?

Thanks,
Saurabh
Jul 02
parent reply Basile B <b2.temp gmx.com> writes:
On Monday, 3 July 2017 at 03:50:14 UTC, Saurabh Das wrote:
 Consider this snippet:

 void main()
 {
     import std.stdio;
     auto a = 6.2151;
     auto b = a * 10000;
     auto c = cast(ulong)b;
     writeln("a: ", typeof(a).stringof, " ", a);
     writeln("b: ", typeof(b).stringof, " ", b);
     writeln("c: ", typeof(c).stringof, " ", c);

     auto x = 62151.0;
     auto y = cast(ulong)x;
     writeln("x: ", typeof(x).stringof, " ", x);
     writeln("y: ", typeof(y).stringof, " ", y);
 }

 The output is:
 a: double 6.2151
 b: double 62151
 c: ulong 62150
 x: double 62151
 y: ulong 62151

 Why does c round off from 62151 to 62150 when casting to ulong?

 Thanks,
 Saurabh
6.251 has no perfect double representation. It's real value is: 6.21509999999999962483343551867E0 Hence when you cast to ulong after the product by 10_000, this is the equivalent of trunc(62150.9999999999962483343551867E0) which gives 62150 CQFD ;-]
Jul 02
next sibling parent reply Saurabh Das <saurabh.das gmail.com> writes:
On Monday, 3 July 2017 at 03:57:25 UTC, Basile B wrote:
 On Monday, 3 July 2017 at 03:50:14 UTC, Saurabh Das wrote:
 [...]
6.251 has no perfect double representation. It's real value is: 6.21509999999999962483343551867E0 Hence when you cast to ulong after the product by 10_000, this is the equivalent of trunc(62150.9999999999962483343551867E0) which gives 62150 CQFD ;-]
That explains it! Thank you.
Jul 02
parent Basile dlang-community <b2.temp gmx.com> writes:
On Monday, 3 July 2017 at 04:06:23 UTC, Saurabh Das wrote:
 On Monday, 3 July 2017 at 03:57:25 UTC, Basile B wrote:
 On Monday, 3 July 2017 at 03:50:14 UTC, Saurabh Das wrote:
 [...]
6.251 has no perfect double representation. It's real value is: 6.21509999999999962483343551867E0 Hence when you cast to ulong after the product by 10_000, this is the equivalent of trunc(62150.9999999999962483343551867E0) which gives 62150 CQFD ;-]
That explains it! Thank you.
There's been a small typo in my answer. "6.251" i meant obviously "6.2151". Anyway it doesn't change anything the most accurate double representation is well the long number i said.
Jul 03
prev sibling parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 3 July 2017 at 03:57:25 UTC, Basile B wrote:
 6.251 has no perfect double representation. It's real value is:
I almost wonder if a BCD, fixed length or alternative for floating point should be an option... Either library, or a hook to change how the FPU works since doubles are suppose to do 16-18 digits of perfect simple floatingpoint for the purposes of money and the like without relying on such imperfect transitions.
Jul 02
next sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Mon, Jul 03, 2017 at 05:38:56AM +0000, Era Scarecrow via Digitalmars-d-learn
wrote:
 On Monday, 3 July 2017 at 03:57:25 UTC, Basile B wrote:
 6.251 has no perfect double representation. It's real value is:
I almost wonder if a BCD, fixed length or alternative for floating point should be an option... Either library, or a hook to change how the FPU works since doubles are suppose to do 16-18 digits of perfect simple floatingpoint for the purposes of money and the like without relying on such imperfect transitions.
From what I've heard, word on the street is to avoid using
floating-point for money calculations, and use fixed-point arithmetic instead (i.e., basically ints / longs, with a built-in decimal point in a fixed position). Inexact representations of certain fractions of tens like the above are one reason for this. I don't think there's a way to change how the FPU works -- the hardware is coded that way and can't be changed. You'd have to build your own library or use an existing one for this purpose. T -- Food and laptops don't mix.
Jul 02
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 3 July 2017 at 06:20:22 UTC, H. S. Teoh wrote:
 On Mon, Jul 03, 2017 at 05:38:56AM +0000, Era Scarecrow via 
 Digitalmars-d-learn wrote:
 I almost wonder if a BCD, fixed length or alternative for 
 floating point should be an option...
 From what I've heard, word on the street is to avoid using 
 floating-point for money calculations, and use fixed-point 
 arithmetic instead (I.e., basically ints / longs, with a 
 built-in decimal point in a fixed position).  Inexact 
 representations of certain fractions of tens like the above are 
 one reason for this.

 I don't think there's a way to change how the FPU works -- the 
 hardware is coded that way and can't be changed.  You'd have to 
 build your own library or use an existing one for this purpose.
It's been a while, i do recall there was BCD options, actually found a few of the instructions; However they are more on loading/storing the value, not on working strictly in that mode. Last i remember seeing references to BCD work was in 2000 or so. I'll have to look further before i find (or fail to find) all that's BCD related. Still if it IS avaliable, it would be an x87 only option and thus wouldn't be portable unless the language or a library offered support.
Jul 03
parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Mon, Jul 03, 2017 at 07:13:45AM +0000, Era Scarecrow via Digitalmars-d-learn
wrote:
 On Monday, 3 July 2017 at 06:20:22 UTC, H. S. Teoh wrote:
[...]
 I don't think there's a way to change how the FPU works -- the
 hardware is coded that way and can't be changed.  You'd have to
 build your own library or use an existing one for this purpose.
It's been a while, i do recall there was BCD options, actually found a few of the instructions; However they are more on loading/storing the value, not on working strictly in that mode. Last i remember seeing references to BCD work was in 2000 or so. I'll have to look further before i find (or fail to find) all that's BCD related. Still if it IS avaliable, it would be an x87 only option and thus wouldn't be portable unless the language or a library offered support.
Wow, that brings back the memories... I used to dabble with BCD (only a little bit) back when I was playing with 8086/8088 assembly language. But I've not heard anything about BCD since that era, and I'm surprised people still know what it is. :-D But all I knew about BCD was in the realm of integer arithmetic. I had no idea such things as BCD floats existed. T -- An imaginary friend squared is a real enemy.
Jul 03
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 4 July 2017 at 00:35:10 UTC, H. S. Teoh wrote:
 On Mon, Jul 03, 2017 at 07:13:45AM +0000, Era Scarecrow via 
 Digitalmars-d-learn wrote:
 On Monday, 3 July 2017 at 06:20:22 UTC, H. S. Teoh wrote:
[...]
 I don't think there's a way to change how the FPU works -- 
 the hardware is coded that way and can't be changed.  You'd 
 have to build your own library or use an existing one for 
 this purpose.
It's been a while, i do recall there was BCD options, actually found a few of the instructions; However they are more on loading/storing the value, not on working strictly in that mode. Last i remember seeing references to BCD work was in 2000 or so. I'll have to look further before i find (or fail to find) all that's BCD related. Still if it IS avaliable, it would be an x87 only option and thus wouldn't be portable unless the language or a library offered support.
Wow, that brings back the memories... I used to dabble with BCD (only a little bit) back when I was playing with 8086/8088 assembly language. But I've not heard anything about BCD since that era, and I'm surprised people still know what it is. :-D But all I knew about BCD was in the realm of integer arithmetic. I had no idea such things as BCD floats existed.
In times of lore, BCD floats were very common. The Sharp Pocket Computer used a BCD float format and writing machine code on them confronts one with the format. The TI-99/4A home computer also used a BCD float format in its Basic interpreter. It had the same properties as the float format of the TI calculators, i.e. 10 visible significant digits (+ 3 hidden digits) and exponents going from -99 to +99. It is only then when I switched to the Apple II Applesoft Basic that I discovered the horrors of binary floating point numbers. Since the generalization of arithmetic co-processors does one only see binary floats anymore.
Jul 04
parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 4 July 2017 at 12:32:26 UTC, Patrick Schluter wrote:
 In times of lore, BCD floats were very common. The Sharp Pocket 
 Computer used a BCD float format and writing machine code on 
 them confronts one with the format. The TI-99/4A home computer 
 also used a BCD float format in its Basic interpreter. It had 
 the same properties as the float format of the TI calculators, 
 I.e. 10 visible significant digits (+ 3 hidden digits) and 
 exponents going from -99 to +99.
If you look at the instruction set for 6502 (and probably similar 4-8bit CPU's) they literally don't deal with anything other than 8bit add/subtraction & other basic binary operators. Without multiplication or division all of that has to be simulated in software. And only needing 10 instructions to do just about everything, well... BCD of course has a big advantage built-in: Because it's all base10, converting BCD to a string and printing it is very fast (as well as precise). And with 1 byte reserved for exponent, raising/lowering the level is also very very easy and goes a very large range. There's also a series of algorithms for calculating some of the more complex functions using small tables or an iteration of shift & add which is implemented on calculators allowing a simpler (and reduced) instruction set or fewer transistors to make calculators work (CORDIC). It's actually pretty fascinating to read about. BCD could still be an option though... I could probably write one; Although with doubles avaliable, you probably don't need it.
Jul 04
prev sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 3 July 2017 at 05:38:56 UTC, Era Scarecrow wrote:
 On Monday, 3 July 2017 at 03:57:25 UTC, Basile B wrote:
 6.251 has no perfect double representation. It's real value is:
I almost wonder if a BCD, fixed length or alternative for floating point should be an option... Either library, or a hook to change how the FPU works since doubles are suppose to do 16-18 digits of perfect simple floatingpoint for the purposes of money and the like without relying on such imperfect transitions.
IBM zSeries and POWER since POWER6 have BCD floating point unit...
Jul 03