www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why are some casts from floating point to integral done differently from others?

reply Aldo Nunez <aldonunez1 gmail.com> writes:
I was testing evaluating cast expressions for a debugger I'm working on, when I
came across this bit of behavior that hopefully Walter or someone else can
explain.

Most conversions in D from floating point to integer are done with the help of
the x87 FP instructions: load FP number, store as integer. This is
understandable.

The following conversions are done differently:
- float, double, real -> uint
- float, double -> ulong

They are done with the help of runtime functions called DBLULNG and DBLULLNG
respectively. They work completely with x86 non-FP instructions. What I don't
like about them is that they produce results that are inconsistent with the way
the other conversions are handled. For example, (cast(uint) -1.0) becomes 0,
whereas (cast(ulong) -1.0L) becomes 0xFFFFFFFFFFFFFFFF and (cast(ushort) -1.0L)
becomes 0xFFFF.
Mar 14 2010
parent reply Don <nospam nospam.com> writes:
Aldo Nunez wrote:
 I was testing evaluating cast expressions for a debugger I'm working on, when
I came across this bit of behavior that hopefully Walter or someone else can
explain.
 
 Most conversions in D from floating point to integer are done with the help of
the x87 FP instructions: load FP number, store as integer. This is
understandable.
 
 The following conversions are done differently:
 - float, double, real -> uint
 - float, double -> ulong
 
 They are done with the help of runtime functions called DBLULNG and DBLULLNG
respectively.

This happens because there are no built-in functions for converting from float to unsigned. Values between int.max and uint.max need to be treated specially. What I don't like about them is that they produce results that are inconsistent with the way the other conversions are handled. For example, (cast(uint) -1.0) becomes 0, whereas (cast(ulong) -1.0L) becomes 0xFFFFFFFFFFFFFFFF and (cast(ushort) -1.0L) becomes 0xFFFF. The cast(uint) case is clearly a bug. Please file it in Bugzilla.
Mar 15 2010
parent reply Aldo Nunez <aldonunez1 gmail.com> writes:
Don Wrote:

 The cast(uint) case is clearly a bug. Please file it in Bugzilla.

I'll file a bug, but...
 This happens because there are no built-in functions for converting from 
 float to unsigned. Values between int.max and uint.max need to be 
 treated specially.
 
 

You're right, but why isn't it done for (float, double -> ulong) like it's done for (real -> ulong), where it's a simple conversion to long plus a fixup. It's not like (float -> real -> ulong) will introduce more precise non-zero bits (or will it?). Then there's the case of (float, double, real -> uint). Why isn't this done like (float, double, real -> ushort), where a simple conversion to int is done, and then the result is truncated to ushort? Wouldn't it work the same to do a simple conversion to long, and then truncate the result to uint? I'm just trying to understand why these simple, yet seemingly just as accurate methods weren't used.
Mar 15 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Aldo Nunez:
 I'll file a bug, but...

If you don't like this you can add a comment after it: http://d.puremagic.com/issues/show_bug.cgi?id=3970 Bye, bearophile
Mar 15 2010
parent Aldo Nunez <aldonunez1 gmail.com> writes:
bearophile Wrote:

 Aldo Nunez:
 I'll file a bug, but...

If you don't like this you can add a comment after it: http://d.puremagic.com/issues/show_bug.cgi?id=3970 Bye, bearophile

Thanks, bearophile! I just did.
Mar 15 2010
prev sibling parent reply Don <nospam nospam.com> writes:
Aldo Nunez wrote:
 Don Wrote:
 
 The cast(uint) case is clearly a bug. Please file it in Bugzilla.

I'll file a bug, but...
 This happens because there are no built-in functions for converting from 
 float to unsigned. Values between int.max and uint.max need to be 
 treated specially.

You're right, but why isn't it done for (float, double -> ulong) like it's done for (real -> ulong), where it's a simple conversion to long plus a fixup. It's not like (float -> real -> ulong) will introduce more precise non-zero bits (or will it?). Then there's the case of (float, double, real -> uint). Why isn't this done like (float, double, real -> ushort), where a simple conversion to int is done, and then the result is truncated to ushort? Wouldn't it work the same to do a simple conversion to long, and then truncate the result to uint? I'm just trying to understand why these simple, yet seemingly just as accurate methods weren't used.

I don't know, but it's probably historical. The real->ulong code is quite recent (about a year old), but the other ones are ancient. They may even come from the 386 days.
Mar 15 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 I don't know, but it's probably historical. The real->ulong code is 
 quite recent (about a year old), but the other ones are ancient. They 
 may even come from the 386 days.

Eh, go back a lot further!
Mar 15 2010
parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 Don wrote:
 I don't know, but it's probably historical. The real->ulong code is 
 quite recent (about a year old), but the other ones are ancient. They 
 may even come from the 386 days.

Eh, go back a lot further!

Actually I suspected it might be from the x87 emulator days. So, the code is probably older than some of the posters to this newsgroup! OT: My all-time favourite bit of code that I maintain is a little piece of x87 asm which dates from 1981. Back then, Intel didn't even sell the x87 directly, you had to buy it by mail-order from a guy in Silicon Valley who lived near the Intel fab. It's great to see that code still running on a quad-core 64 bit CPU! The app that was converted to Pascal at some point before the 90's, but all of that's gone now. Yet the asm survived (with just AX->EAX->RAX)! It was a fine piece of work.
Mar 15 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 Walter Bright wrote:
 Don wrote:
 I don't know, but it's probably historical. The real->ulong code is 
 quite recent (about a year old), but the other ones are ancient. They 
 may even come from the 386 days.

Eh, go back a lot further!

Actually I suspected it might be from the x87 emulator days. So, the code is probably older than some of the posters to this newsgroup! OT: My all-time favourite bit of code that I maintain is a little piece of x87 asm which dates from 1981. Back then, Intel didn't even sell the x87 directly, you had to buy it by mail-order from a guy in Silicon Valley who lived near the Intel fab. It's great to see that code still running on a quad-core 64 bit CPU! The app that was converted to Pascal at some point before the 90's, but all of that's gone now. Yet the asm survived (with just AX->EAX->RAX)! It was a fine piece of work.

The Digital Mars C compiler was started in 1982, and a lot of it still survives in the code base (library & compiler). The evolution of the human brain is not done by replacing structures with new ones, but by putting new layers over the old ones and overriding them. Hence, we all have a notochord, and a dinosaur brain, etc. You can see that in the back end code; the original design and structure is intact, it's just been layered over. Maybe some day I should dig up NWC 1.0 and post it! The D front end, however, is radically different from the C front end.
Mar 15 2010