# How to do a particular conversion?

Show 80 post(s) from this thread on one page
Page 2 of 2 First 12
• 09-10-2019
flp1969
Nope chistop... A little test, shall we:

Code:

```#include <stdint.h> int64_t f( double x ) { return x; } int g( double x, int64_t y ) { return (x - y) * 100; }```
With this you'll get:

Code:

```f:   cvttsd2si rax, xmm0   ret g:   pxor  xmm1, xmm1   cvtsi2sdq xmm1, rdi   subsd xmm0, xmm1   mulsd xmm0, QWORD PTR .LC0[rip]  ; .LC0 hold the encoded double 100.0   cvttsd2si eax, xmm0   ret```
The first one, CVTTSDSI is a convertion WITH truncation, the second one (on g()) just gets the integral part again, but the calculation is made with rounding on... What I did is to strip the integer part of the double value... 0.3, indeed isn't representable in floating point, nor 0.1, 0.2, 0.4, 0.6, 0.7, 0.8 or 0.9. Floating point is a representation of a FRACTION in the format:

Attachment 15832

Where s, f and e are integers (encoded in floating point structure) and P is the precision of the type, in bits (53 for double). There is no f and e which will give you exactly 0.3.
• 09-10-2019
christop
Well yes, of course, binary floating point cannot accurately represent 0.3 (just like decimal cannot accurately represent 1/3, 0.3333...).

My point was that if the double-precision approximation of 0.3 (0.29999999999999998889776975374843459576368331909 1796875) is converted to integral and fractional components with proper rounding, then you should get 9 and 30 (out of 100). This is the same problem you would face if you were given a value of, say, 0.4999999.... Properly rounded to two digits after the decimal point, it would be 0.50. Truncating gives you 0.49.
• 09-10-2019
flp1969
Quote:

Originally Posted by christop
Well yes, of course, binary floating point cannot accurately represent 0.3 (just like decimal cannot accurately represent 1/3, 0.3333...).

My point was that if the double-precision approximation of 0.3 (0.29999999999999998889776975374843459576368331909 1796875) is converted to integral and fractional components with proper rounding, then you should get 9 and 30 (out of 100). This is the same problem you would face if you were given a value of, say, 0.4999999.... Properly rounded to two digits after the decimal point, it would be 0.50. Truncating gives you 0.49.

Ok... assuming all values are positive there is an old trick: If you want 2 decimal places as "precision" you could do:

Code:

`f = (( t - i ) + 0.005)*100;`
Here t is double, f is int and i is int (or int64_t, in my case)... But there is no "rouding" of a floating point value without this trick because there is no values representable between 0.299999999999999988897769753748434595763683319091 796875 and 0.300000000000000044408920985006261616945266723632 8125 in 'double' (you see? I can use 'bc' as well! hehe)...
• 09-10-2019
Hodor
Quote:

Originally Posted by flp1969
Here t is double, f is int and i is int (or int64_t, in my case)... But there is no "rouding" of a floating point value without this trick because there is no values representable between 0.299999999999999988897769753748434595763683319091 796875 and 0.300000000000000044408920985006261616945266723632 8125 in 'double' (you see? I can use 'bc' as well! hehe)...

I don't really understand the issue here

Code:

```#include <stdio.h> #include <math.h> int main(void) {     const double testvalues[] = {         3.14, 9.3, 9.28, 9.29, 1.1, 0.1, 0.9, 1.0/5, 1.0/3,         0.299999999999999988897769753748434595763683319091796875     };     double t;     int i, f;     unsigned it;         for (it = 0; it < sizeof testvalues / sizeof testvalues[0]; ++it) {         t = testvalues[it];         i = t;         f = round((t - i) * 100.0);         //f = ((t - i) + 0.005) * 100;         printf("%f: %d, %d\n", t, i, f);     }         return 0; }```
gives

Code:

```3.140000: 3, 14 9.300000: 9, 30 9.280000: 9, 28 9.290000: 9, 29 1.100000: 1, 10 0.100000: 0, 10 0.900000: 0, 90 0.200000: 0, 20 0.333333: 0, 33 0.300000: 0, 30```
Which is what is expected (?)
• 09-11-2019
flp1969
Quote:

Originally Posted by Hodor
I don't really understand the issue here

Notice I didn't call a libm function. No extra libraries needed to be linked... No round() call... which is a little bit faster.
• 09-11-2019
christop
Quote:

Originally Posted by Hodor
I don't really understand the issue here

Code:

```#include <stdio.h> #include <math.h> int main(void) {     const double testvalues[] = {         3.14, 9.3, 9.28, 9.29, 1.1, 0.1, 0.9, 1.0/5, 1.0/3,         0.299999999999999988897769753748434595763683319091796875     };     double t;     int i, f;     unsigned it;         for (it = 0; it < sizeof testvalues / sizeof testvalues[0]; ++it) {         t = testvalues[it];         i = t;         f = round((t - i) * 100.0);         //f = ((t - i) + 0.005) * 100;         printf("%f: %d, %d\n", t, i, f);     }         return 0; }```
gives

Code:

```3.140000: 3, 14 9.300000: 9, 30 9.280000: 9, 28 9.290000: 9, 29 1.100000: 1, 10 0.100000: 0, 10 0.900000: 0, 90 0.200000: 0, 20 0.333333: 0, 33 0.300000: 0, 30```
Which is what is expected (?)

Code:

`0.999000: 0, 100`
Oops!

You need to round t (either with the round() function or by adding 0.005) before converting it to a integral and fractional parts.

Even then there may be edge cases where conversion gives a wrong result. Floating point can be tricky! But it should be easy enough to iterate over all possible values of a double between about 0.005 and 9223372036854775000 (the maximum value of a double-precision number that fits in a signed 64-bit integer) to make sure they're all converted properly. There's only about 324259173170675712 values to check, so you could check them all in about 10 years, assuming you can check one billion values per second.
• 09-11-2019
flp1969
Quote:

Originally Posted by christop
there's only about 324259173170675712 values to check, so you could check them all in about 10 years, assuming you can check one billion values per second.

bwahahahahahahahahahaha!!!! :)
• 09-11-2019
Hodor
Quote:

Originally Posted by christop

Code:

`0.999000: 0, 100`
Oops!

You need to round t (either with the round() function or by adding 0.005) before converting it to a integral and fractional parts.

Even then there may be edge cases where conversion gives a wrong result. Floating point can be tricky! But it should be easy enough to iterate over all possible values of a double between about 0.005 and 9223372036854775000 (the maximum value of a double-precision number that fits in a signed 64-bit integer) to make sure they're all converted properly. There's only about 324259173170675712 values to check, so you could check them all in about 10 years, assuming you can check one billion values per second.

For 0.999 in this scenario I would expect the answer to be 0, 100 so that's not an oops. Even if you disagree, the point of my quick and dirty "test" program was not to handle every single edge case but to demonstrate that what was being discussed (i.e. that working with 0.3 could never work) didn't make sense.
• 09-11-2019
Hodor
Quote:

Originally Posted by flp1969
Notice I didn't call a libm function. No extra libraries needed to be linked... No round() call... which is a little bit faster.

Well, the discussion wasn't about using or not using library calls so I'm not sure what you point is. Plus I don't think your method is going to work very well for amounts such as -0.33 because it'll "round" in the wrong direction
• 09-11-2019
flp1969
Quote:

Originally Posted by Hodor
Well, the discussion wasn't about using or not using library calls so I'm not sure what you point is. Plus I don't think your method is going to work very well for amounts such as -0.33 because it'll "round" in the wrong direction

Ok... forget everything about it then... good luck!
• 09-11-2019
Hodor
Quote:

Originally Posted by flp1969
Ok... forget everything about it then... good luck!

Why would I want to forget about it? It's interesting if only because there are people out there insane enough to use floating point numbers for dealing with money :D
• 09-19-2019
zach
This thread has been closed some time ago. Please don't keep it going endlessly. Zach.
Show 80 post(s) from this thread on one page
Page 2 of 2 First 12