« first day    last day (18 days later) » 

3:27 AM
In this page (which implements IEEE754 with arbitrary precision math -- i.e. probably no error) enter a decimal number of "0.3333333333333333333333333333" (yes a lot of digits) and the resulting double decimal with 21 digits will be "0.333333333333333314829" which clearly is not equal to "0.33…". So, no, not the same.
However, with 16 digits, the result is "0.3333333333333333" which is more compatible with what an human would expect to see. No, the number is not more precise, but it is more "human compatible".
 
 
6 hours later…
9:15 AM
@isaac note that it's 21 decimal digits. Those 0x1.555555p-2 representations use hexadecimal for the mantis and decimal for the (power of 2) exponent.
You could write something like:<pre>
```
`#include <stdlib.h>
#include <stdio.h>
void printld(long double d) {
unsigned char *p = (unsigned char*) &d;
for (int i = 0; i < sizeof(d); i++)
printf("%02x", p[i]);
printf(" %La %.80Lg\n", d, d);
}

int main(int argc, char *argv[]) {
long double x = 1.L/3L, y;
y = strtold(argv[1], 0);
printld(x);
printld(y);
return 0;
}
`
if you want to play with it. (I don't know how to format code in chat sorry).
@isaac for double, you need 17 digits. 21 digits is for the 80bit extended precision ones. That yields 0.33333333333333331 for 1/3 which is what zsh gives you. If you remove the trailing 31 (like yash does), that becomes a different floating number that is further away from 1/3 than 0.33333333333333331 is (0.333333333333332981762708868700428865849971771240234375)
If you only remove only the 1, that yields the same number. OK that time, but if you change it to 5/9 for instance, 0.5555555555555555 yields a different number than 0.55555555555555558 which is further away (0.55555555555555546920487586248782463371753692626953125 vs 0.5555555555555555802271783250034786760807037353515625)
IOW, even though 0.55555555555555558 looks worse than 0.5555555555555555, it is closer to the truth (5/9)
I'd agree 198.40000000000001 looks neither better nor is closer to the truth than 198.4 though (both of which yield the same 198.400000000000005684341886080801486968994140625 double)
I don't know if there's an easy way to fix that. May be something like: if the last before last digit is a 0, check if using one fewer significant digit yields the same number (to cover the xxx.xx00000x cases) and some other approach to cover the xxx.999999x case.
 
 
7 hours later…
4:36 PM
No, there is no simple way to solve that and yes, removing digits reduces exactness. That is the nature of floating point math. What do you want me to say?
The code you presented segfaults here. I'll try to repair it but my coding abilities are not so good. If I get it to work I'll post something about it. @StéphaneChazelas
 
5:11 PM
Ok, I found the problem with the code (it needed an argument).
Please understand that even if the long double is a 16 byte (128 bit) entity it is only an 80 bit float. Read in wikipedia With the GNU C Compiler, long double is 80-bit extended precision on x86 processors regardless of the physical storage used for the type (which can be either 96 or 128 bits). And I am compiling the code in linux, not an SPARC or a PowerPC.
An 80 bit float only has 64 bit for the mantissa. A 64 bit mantissa has an effective range of precision of around 19 digits awk 'BEGIN{print(1/2^64)}' yields 5.42101e-20
 
5:32 PM
yes it's generally 80bit on x86 for most compilers (the extended precision ones). It can be 128 bit (the quadruple precisions on some systems). On Windows it's 64 bits. That has been discussed before. Like the fact that you need 21 digits with 80 bits ones and 36 bits for the the 128 bit ones.
 
What the 21 digits is trying to mean is that if you start with a given decimal with 21 digits (lets use 0.5555555555555555555555) you will end with the exact same decimal after two conversions: to binary and back to decimal if the IEEE754 implementation is correct. Try this code with program 0.5555555555555555555555 to see the results.
<pre>```
 
Yes, what I mean is that for a decimal representation to be faithful, you need the 21 bits, otherwise, you're not sure you can go back to the same number (to the same long double)
 
<pre>```
#include <stdlib.h>
#include <stdio.h>
void printld(long double d) {
unsigned char *p = (unsigned char*) &d;
for (int i = 0; i < sizeof(d); i++)
printf("%02x", p[i]);
printf(" %La %.22Lg\n", d, d);
}

int main(int argc, char *argv[]) {
long double x = 1.L/3L, y = 0.L;
if (argc == 2 ) y = strtold(argv[1], 0);
printf("A long double is an entity of = %lu bytes\n",sizeof(x));
printld(x);
if (argc == 2 ) printld(y);
return 0;
}
```</pre>
No, it going back to the same decimal digits representation, not binary.
 
Again, see how 0.3333333333333333333 and 0.333333333333333333333 yield two different numbers with long doubles
 
But in trying the program with 21 digits (0.555555555555555555555) yields 0.555555555555555555561 (the same 21 digits). That means that the implementation is not a faithful implementation of IEEE754 in that it fails the full round trip.
And yes, different length decimals will yield different binary values, nothing odd in that.
Note however that the 21 digits 0.333333333333333333333 you propose (use program 0.333333333333333333333 to see it) has the same binary representation that a 1/3 has. That is the maximum precision possible: 0.3333333333333333333424
Again, a round trip means going back to the same decimal digits representation.
That is why the very long number you present here: (0.333333333333332981762708868700428865849971771240234375) has absolutely NO meaning. That's why it deviates from a repeated 3 just after only 14 digits (what follows is a 2981… etc). It is not a correct 128 bit IEEE754 float, it is an extended 80bit float. No more than 21 decimal digits have sense or may mean something. Using a printf of 80 decimal digits (%.80Lg) outputs a lot of digits, but mean nothing real, are only noise of some code.
 
6:47 PM
Do we agree that this ends this discussion? @StéphaneChazelas
 
 
2 hours later…
8:46 PM
@isaac It looks like I'm failing to communicate what I mean to you. I may add a Q&A when I have a moment explaining why zsh gives the result of floating point arithmetic expansions with 17 significant digits and why it has good reasons to do so even if that causes those artefacts. I agree the discussion is over here.
 
Artifacts should not appear for 1/3 with a correct IEEE754 implementation.
Nor should with 17 digits of 198.4. Even the gcc implementation of IEEE754 which is not correct as we already found out produce 20 reasonably correct digits (198.39999999999999999) (try program 198.4). Trimming it to 17 digits should round up the last 9 to produce 198.4 (round trip correct). It doesn't.
 

« first day    last day (18 days later) »