1. poke8 problems : 64-bit numbers in a 53-bit language
- Posted by SDPringle Sep 26, 2015
- 1701 views
Euphoria on 32-bit machines has a problem. We use 64-bit values on a 53-bit number language. Now numbers like -1, which as a signed 64-bit number is 0xffff_ffff_ffff_ffff. You can poke -1 with poke8, but that number is actually a 32 bit value so no problem. You can even poke values such as 0xffff_ffff_ffff_f800 with poke8 on a 32-bit system. As soon as you employ things like numbers that cannot be represented in a double exactly, the number in the backend becomes 0.
The difference is if the number you use cannot be represented exactly in a eudouble, then the value becomes zero before it gets a chance to be written to memory.
The user has to avoid this kind of thing. It rather makes sense not to allow you to write a number when the value is imprecise. At the same time, writing 0 rather than what the user supplied is just wrong. It seems to be that this should be an error condition. It must be documented and caught by the backend.
SD Pringle
2. Re: poke8 problems : 64-bit numbers in a 53-bit language
- Posted by petelomax Sep 27, 2015
- 1686 views
Obviously an error of some sort is unavoidable, though 0 is a bit extreme, and as you say what it really needs is documenting properly. Here is what I wrote in the documentation of peek for Phix:
The peek8s and peek8u routines are not intended for use on 32-bit; for more details see below.
...
While somewhat flakey versions of peek8s and peek8u now exist in 32-bit Phix they are not formally supported; any code that is required to run on both 32 and 64 bit should stick to using peek4s/u and below. Atoms in 64-bit Phix use 80-bit floats that have a maximum precision of 64 bits, perfect for peek8s/u. However, atoms in 32-bit Phix use 64-bit floats that have a maximum precision of 53 bits, hence loss of data is avoided by making these routines return a two-element pair of unsigned dword-sized blocks when necessary, as the following example (which assumes little endian) shows. When peek8s or peek8u is used in a 32-bit application (not recommended and not officially supported), it checks for precision loss:
poke(addr,{0,0,0,0,0,0,0,#80,1,0,0,0,0,0,0,#80}) result = peek8u({addr,2})
On 64-bit result gets set to {#8000000000000000,#8000000000000001}
On 32-bit result gets set to {#8000000000000000,{#80000000,#00000001}}.
...
and obviously it would all be far easier if you just did it all using peek4s/u and poke4s/u, as I recommended in the first place.
...
In truth, there are two reasons why peek8s/u exist at all on 32-bit: peek8u is used (lightly and in a non-critical manner) when cross-compiling, ie when a 32-bit Phix is asked, via a format directive, to create a 64-bit executable, and secondly so that code such as
if machine_bits()=32 then r = peek4u(k) else -- machine_bits()=64 r = peek8u(k) end if
compiles cleanly rather than complains that peek8u does not exist, even though you are not going to call it because you understand and accept that it can be a bit flakey on 32-bit.
The other thing is that you cannot catch anything in the backend/poke8: there is no way it could tell that you've dropped some precision somewhere and the number you passed it isn't quite what you meant. Unless you meant there are some numbers that should work but don't, in which case a) I wouldn't mind testing them on Phix, and b) surely it would be just as easy to fix it so it works right as trap some "error".
Pete
3. Re: poke8 problems : 64-bit numbers in a 53-bit language
- Posted by SDPringle Sep 28, 2015
- 1571 views
I was getting numbers close to but not as big as 264. Give a value like 0xffff_ffff_ffff_f000, and that will go into memory as is and be peeked back in. So, I experimented with poking 0xffff_ffff_ffff_fc00 into memory and peeking from that place got me 0.
Now, the value is read by the scanner as a very large positive value. It is not until it is converted to a 64-bit int that it becomes 0. If the scanner were rounding it to 0, the following test would pass as 0 = 0. This happens completely inside do_poke8() in be_execute.c and has nothing to do with how peek8u works.
poke8( ptr, 0xffff_ffff_ffff_fc00 ) test_equal( "poke8/peek8u 54-bit number", 0xffff_ffff_ffff_fc00, peek8u( ptr ) )
The value is not rounded to something bigger than the biggest 64-big unsigned int because if it were the program would halt because of a limits test the value is put to before an attempt at conversion is made. Now the unsigned 64-bit int is big enough to hold the value.
Strange.
4. Re: poke8 problems : 64-bit numbers in a 53-bit language
- Posted by SDPringle Sep 29, 2015
- 1544 views
I think I have figured it out.
The maximum double value and minimum double value in the header files are not applicable to 32-bit processors. That is MAX_LONGLONG_DBL should not be #FFFF_FFFF_FFFF_FFFF but rather #FFFF_FFFF_FFFF_F800 because of the limits of 64-bit atoms. Loss of precision is one thing but poking a very big value and instead getting zero in memory is another. We should look at the lower bound as well.
Shawn Pringle
5. Re: poke8 problems : 64-bit numbers in a 53-bit language
- Posted by petelomax Sep 29, 2015
- 1531 views
but rather #FFFF_FFFF_FFFF_F800 because of the limits of 64-bit atoms.
That's interesting. Phix craps out at #7FFF_FFFF_FFFF_FC00, some kind of sign/1 bit shift thing. It also strikes me that the 0 is in effect a rounding up to #1_0000_0000_0000_0000.
You are quite right, of course: the real culprit here is poke8 quietly doing something stupid rather then crashing. I think I've been looking at this from the wrong side.
Cheers,
Pete
PS: this post isn't meant to help you either, just saying thanks