3

i want to convert the fractional part of a double value with precision upto 4 digits into integer. but when i do it, i lose precision. Is there any way so that i can get the precise value?

#include<stdio.h>
int main()
{
    double number;
    double fractional_part;
    int output;
    number = 1.1234;
    fractional_part = number-(int)number;
    fractional_part = fractional_part*10000.0;
    printf("%lf\n",fractional_part);
    output = (int)fractional_part;
    printf("%d\n",output);
    return 0;
}

i am expecting output to be 1234 but it gives 1233. please suggest a way so that i can get desired output. i want the solution in C language.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
Atul Kumar Verma
  • 369
  • 3
  • 8
  • 23
  • 1
    You just used the words "double" or "float" and "precise value" in the same sentence. Bad mojo. You're method is OK, but add 0.5 before you convert to int, because that's probably truncating rather than rounding. Better yet, use round() explicitly. That will give you the closest value. "The" precise value doesn't exist. – Lee Daniel Crocker Jun 23 '13 at 09:37

4 Answers4

4

Assuming you want to get back a positive fraction even for negative values, I'd go with

(int)round(fabs(value - trunc(value)) * 1e4)

which should give you the expected result 1234.

If you do not round and just truncate the value

(int)(fabs(value - trunc(value)) * 1e4)

(which is essentially the same as your original code), you'll end up with the unexpected result 1233 as 1.1234 - 1.0 = 0.12339999999999995 in double precision.

Without using round(), you'll also get the expected result if you change the order of operations to

(int)(fabs(value * 1e4 - trunc(value) * 1e4))

If the integral part of value is large enough, floating-point inaccuracies will of course kick in again.

You can also use modf() instead of trunc() as David suggests, which is probably the best approach as far as floating point accuracy goes:

double dummy;
(int)round(fabs(modf(value, &dummy)) * 1e4)
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • @DavidRF: the first version will return the expected `1234`; the second one returns `1233` because of floating-point semantics; I'll update the answer... – Christoph Jun 23 '13 at 12:10
  • These do not always produce the correct answer. Truncation does not, as the example in the question shows 1234 is wanted for `1.1234`, but truncation produces 1233. For rounding, consider the value 0.1026499999999999912514425659537664614617824554443359375. Then the first four decimal digits of the fraction are 1026. But the rounding method produces 1027, when `double` arithmetic (IEEE 754 64-bit binary) is used. – Eric Postpischil Jun 23 '13 at 22:31
  • @EricPostpischil: 0.1026499999999999912514425659537664614617824554443359375 and 0.10265 are the same number as far as double precision is concerned as they only differ in the 56th binary digit (off-by-one errors notwithstanding); with the 53-bit limit of doubles, one just has to accept that some things aren't possible... – Christoph Jun 24 '13 at 05:33
  • @EricPostpischil: I see your point that using `round()` won't necessarily do the right thing if Atul wants truncation (which he did not specify in his answer, so claiming my answer is wrong is a bit premature); if truncation is indeed what he wants, I believe you'll have to mess around with `nextafter()` and flip a coin in ambiguous cases... – Christoph Jun 24 '13 at 05:42
  • @Christoph: (a) I did not state this answer is wrong. I stated the code in it does not always produce the correct answer. This is undeniable fact, since I demonstrated it. (b) 0.1026499999999999912514425659537664614617824554443359375 and 0.10265 are not the same. IEEE 754 is quite specific about what values are represented, and 64-bit binary represents the former and does not represent the latter. (c) One does not have to accept that this is not possible. When the former value is printed using `%.4f` using Mac OS X 10.6.8 and its tools, the result is “0.1026”. – Eric Postpischil Jun 24 '13 at 11:22
  • @EricPostpischil: the problem is that while `0.1026499... != 0.10265`, we nevertheless have `0.1026499... * 1e4 == 0.10265 * 1e4`; discarding excess precision via `(trunc(frac * 16384.0) * 1e4) / 16384.0)` works for Atul's and your sample values, but no guarantees that this doesn't mess up other edge cases... – Christoph Jun 24 '13 at 13:43
  • 1
    @Christoph: Yes, there is a problem. No, it is not insolvable. There is a widely known paper about it, [Correctly Rounded Binary-Decimal and Decimal-Binary Conversions by David M. Gay](http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.4049). This answer presents code that produces incorrect results. Methods to get correct results are known and published. If you want a quick-and-dirty solution and have a good C implementation, you can use `sprintf` to convert the floating-point number to decimal and `scanf` to convert to an integer. – Eric Postpischil Jun 24 '13 at 13:57
1

number= 1.1234, whole=1, fraction=1234

int main()
{
 double number;
 int whole, fraction;
 number = 1.1234;
 whole= (int)number;
 fraction =(int)(number*10000);
 fraction = fraction-(whole *10000);
 printf("%d\n",fraction);
 printf("%d\n",whole);
 return 0;
}
OnePunchMan
  • 720
  • 15
  • 33
  • I agree with your example. But if I don't know the number and I don't know how large is the fractional part? – Romulus Nov 26 '13 at 22:59
  • @RemusAvram check this code then http://stackoverflow.com/a/18517555/2508414 well for us starter that code should work fine, if we try to write a code for a very large number (as far as i know) there is no answer.. those people doing research and high level of programming can do. but so far i haven't found better logic then the one i have implemented. – OnePunchMan Nov 28 '13 at 09:24
1

A solution for any number could be:

#include <cmath>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{ 
float number = 123.46244;
float number_final;
float temp = number;  // keep the number in a temporary variable
int temp2 = 1;        // keep the length of the fractional part

while (fmod(temp, 10) !=0)   // find the length of the fractional part
{
    temp = temp*10;
    temp2 *= 10;
}

temp /= 10;       // in tins step our number is lile this xxxx0
temp2 /= 10;
number_final = fmod(temp, temp2);

cout<<number_final;

getch();
return 0;
}
Romulus
  • 1,150
  • 3
  • 16
  • 26
0

Use modf and ceil

#include <stdio.h>
#include <math.h>

int main(void)
{
    double param, fractpart, intpart;
    int output;

    param = 1.1234;
    fractpart = modf(param , &intpart);
    output = (int)(ceil(fractpart * 10000));
    printf("%d\n", output);

    return 0;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94