Jump to page: 1 2 3
Thread overview
Handling big FP numbers
Feb 09
Murilo
Feb 09
Murilo
Feb 09
Murilo
Feb 09
DanielG
Feb 09
Murilo
Feb 09
Murilo
Feb 09
DanielG
Feb 09
Murilo
Feb 09
DanielG
Feb 09
Murilo
Feb 09
Murilo
Feb 10
Murilo
Feb 10
Dennis
Feb 10
Murilo
5 days ago
Simen Kjærås
February 09
Why is it that in C when I attribute the number 99999912343000007654329925.7865 to a double it prints 99999912342999999470108672.0000 and in D it prints 99999912342999999000000000.0000 ? Apparently both languages cause a certain loss of precision(which is part of converting the decimal system into the binary system) but why is it that the results are different?
February 09
On Saturday, 9 February 2019 at 02:12:29 UTC, Murilo wrote:
> prints

Two likely reasons: the D compiler does compile time stuff at 80 bit, whereas the C++ one probably uses 64 bit, and the D default print rounds more aggressively than default C++ printing.

It is useful to put stuff in runtime variables of type `double` to avoid the differnt bit stuff, and print with printf in both languages to ensure that is the same.
February 09
On Saturday, 9 February 2019 at 02:42:09 UTC, Adam D. Ruppe wrote:
> On Saturday, 9 February 2019 at 02:12:29 UTC, Murilo wrote:
>> prints
>
> Two likely reasons: the D compiler does compile time stuff at 80 bit, whereas the C++ one probably uses 64 bit, and the D default print rounds more aggressively than default C++ printing.
>
> It is useful to put stuff in runtime variables of type `double` to avoid the differnt bit stuff, and print with printf in both languages to ensure that is the same.

Hi, thanks for the information. But I used the type double in D which is supposed to be only 64 bits long and not 80 bits long, the type real is the one which is supposed to be 80 bits long. Right?
February 09
On Saturday, 9 February 2019 at 02:46:52 UTC, Murilo wrote:
> But I used the type double in D which is supposed to be only 64 bits long and not 80 bits long, the type real is the one which is supposed to be 80 bits long. Right?

Right, BUT the compile time stuff is done before that.

double a = 1.0 * 2.0;

The 1.0*2.0 is done as real inside the compiler, then the *result* is assigned to the 64 bit double.

Whereas in a C++ compiler, that would be done 64 bit throughout. So the different intermediate rounding can give a different result.

(The `real` thing in D was a massive mistake. It is slow and adds nothing but confusion.)
February 09
On Saturday, 9 February 2019 at 02:54:18 UTC, Adam D. Ruppe wrote:
> On Saturday, 9 February 2019 at 02:46:52 UTC, Murilo wrote:
>> But I used the type double in D which is supposed to be only 64 bits long and not 80 bits long, the type real is the one which is supposed to be 80 bits long. Right?
>
> Right, BUT the compile time stuff is done before that.
>
> double a = 1.0 * 2.0;
>
> The 1.0*2.0 is done as real inside the compiler, then the *result* is assigned to the 64 bit double.
>
> Whereas in a C++ compiler, that would be done 64 bit throughout. So the different intermediate rounding can give a different result.
>
> (The `real` thing in D was a massive mistake. It is slow and adds nothing but confusion.)

ahhh okay, thanks for clearing it up. is there a way to bypass that?
February 08
On Sat, Feb 09, 2019 at 02:12:29AM +0000, Murilo via Digitalmars-d-learn wrote:
> Why is it that in C when I attribute the number 99999912343000007654329925.7865 to a double it prints 99999912342999999470108672.0000 and in D it prints 99999912342999999000000000.0000 ? Apparently both languages cause a certain loss of precision(which is part of converting the decimal system into the binary system) but why is it that the results are different?

It's not only because of converting decimal to binary, it's also because double only has 64 bits to store information, and your number has far more digits than can possibly fit into 64 bits.  Some number of bits are used up for storing the sign and exponent, so `double` really can only store approximately 15 decimal digits.  Anything beyond that simply doesn't exist in a `double`, so attempting to print that many digits will inevitably produce garbage trailing digits.  If you round the above outputs to about 15 digits, you'll see that they are essentially equal.

As to why different output is produced, that's probably just an artifact of different printing algorithms used to output the number.  There may be a small amount of difference around or after the 15th digit because D implicitly converts to `real` (which on x86 is the 80-bit proprietary FPU representation) for some operations and rounds it back, while C only operates on 64-bit double.  This may cause some slight difference in behaviour around the 15th digit or so.

Either way, it is not possible for `double` to hold more than 15 decimal digits, and any output produced from the non-existent digits following that is suspect and probably just random garbage.

If you want to hold more than 15 digits, you'll either have to use `real`, which depending on your CPU will be 80-bit (x86) or 128-bit (a few newer, less common CPUs), or an arbitrary-precision library that simulates larger precisions in software, like the MPFR module of libgmp. Note, however, that even even 80-bit real realistically only holds up to about 18 digits, which isn't very much more than a double, and still far too small for your number above.  You need at least a 128-bit quadruple precision type (which can represent up to about 34 digits) in order to represent your above number accurately.


T

-- 
The fact that anyone still uses AOL shows that even the presence of options doesn't stop some people from picking the pessimal one. - Mike Ellis
February 09
On Saturday, 9 February 2019 at 03:03:41 UTC, H. S. Teoh wrote:
> It's not only because of converting decimal to binary, it's also because double only has 64 bits to store information, and your number has far more digits than can possibly fit into 64 bits.

Adding to that, here's a nice little online calculator that will show the binary representation of a given decimal number:

https://www.h-schmidt.net/FloatConverter/IEEE754.html


February 08
On Sat, Feb 09, 2019 at 02:54:18AM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote: [...]
> (The `real` thing in D was a massive mistake. It is slow and adds
> nothing but confusion.)

Yeah, it is also the only variable-width built-in type in D, which makes it a wart in an otherwise elegant system of fixed-width types.

And 80-bit extended precision is non-standard and non-conformant to IEEE 754, and who other than Intel engineers can tell how it behaves in corner cases?

It also causes std.math to make a laughing stock of D, because the majority of math functions implicitly convert to real and cast the result back to the source type, thus representing a hidden performance cost even if the caller explicitly used float precisely to reduce the cost of computing at a higher precision. And it prevents the optimizer from, e.g., taking advantage of SSE instructions for faster computation with float/double.


T

-- 
If lightning were to ever strike an orchestra, it'd always hit the conductor first.
February 09
On Saturday, 9 February 2019 at 03:03:41 UTC, H. S. Teoh wrote:
> On Sat, Feb 09, 2019 at 02:12:29AM +0000, Murilo via Digitalmars-d-learn wrote:
>> Why is it that in C when I attribute the number 99999912343000007654329925.7865 to a double it prints 99999912342999999470108672.0000 and in D it prints 99999912342999999000000000.0000 ? Apparently both languages cause a certain loss of precision(which is part of converting the decimal system into the binary system) but why is it that the results are different?
>
> It's not only because of converting decimal to binary, it's also because double only has 64 bits to store information, and your number has far more digits than can possibly fit into 64 bits.  Some number of bits are used up for storing the sign and exponent, so `double` really can only store approximately 15 decimal digits.  Anything beyond that simply doesn't exist in a `double`, so attempting to print that many digits will inevitably produce garbage trailing digits.  If you round the above outputs to about 15 digits, you'll see that they are essentially equal.
>
> As to why different output is produced, that's probably just an artifact of different printing algorithms used to output the number.  There may be a small amount of difference around or after the 15th digit because D implicitly converts to `real` (which on x86 is the 80-bit proprietary FPU representation) for some operations and rounds it back, while C only operates on 64-bit double.  This may cause some slight difference in behaviour around the 15th digit or so.
>

Now, changing a little bit the subject. All FPs in D turn out to be printed differently than they are in C and in C it comes out a little more precise than in D. Is this really supposed to happen?


February 09
On Saturday, 9 February 2019 at 03:21:51 UTC, Murilo wrote:
> Now, changing a little bit the subject. All FPs in D turn out to be printed differently than they are in C and in C it comes out a little more precise than in D. Is this really supposed to happen?

Like I said in my first message, the D default rounds off more than the C default. This usually results in more readable stuff - the extra noise at the end is not that helpful in most cases.

But you can change this with the format specifiers (use `writefln` instead of `writeln` and give a precision argument) or, of course, you can use the same C printf function from D.
« First   ‹ Prev
1 2 3