问题
Sample code:
int main() {
float f = 123.542;
int i = (int)f;
printf("%d\n",i);
}
回答1:
123.3443 can't be exactly represented by a floating-point number -- in a 32-bit float, it's effectively represented as 16166984 / 131072
, which is actually 123.34429931640625, not 123.3443. (It's off by around 6.8 x 10^-7.)
If this is really the result you want (which it's probably not), take a look at how IEEE-754 floats work, and pull out your favorite arbitrary-precision math suite. Once you understand what's going on "behind the scenes", generating an exact representation shouldn't be too hard. Generating a "close enough" rounded representation is actually much harder. :)
回答2:
int i = (int) (f * 10000 + 0.5);
回答3:
Multiply the float
by 10^x
where x
is how many digits after the decimal you want and then cast to int
.
回答4:
If you don't need to do any repetitive processing of the converted number and are only looking to convert the numbers into an integer, the easiest way is to use sprintf, then sum up the decimals with a for loop using power of 10 rules. If you need "exact precision" for math, use a BCD. The following algorithm will allow you to truncate the number of digits for "exact precision".
#include "math.h"
long ConvertToScaledInteger (float value, int significantDigits = -1)
{
// Note: for 32-bit float, use long return and for double use long long.
if (significantDigits < 1) // Ditch the '-' and the '.'
significantDigits += 2;
else
++significantDigits; // Ditch the '.'
char* floatingPointString = malloc(sizeof (char) * (4 + FLT_MANT_DIG - FLT_MIN_EXP));
/*< This solution is for a 32-bit floating point number. Replace FLT
with DBL, and it will produce the max number of chars in a 64-bit
float string. */
if (significantDigits < 0) //< Then use all of the float's digits.
{
sprintf (floatingPointString , "%f", floatingPointNumber);
}
else //< Then truncate the number of decimal places.
{
char decimalPlaceString[9];
char percentString = "%\0";
sprintf (decimalPlaceString, "%s%if", percentString , significantDigits);
sprintf (floatingPointString , decimalPlaceString, value);
}
int stringLength = strlen (floatingPointString),
index;
long returnValue = 0;
double powerOfTen = 10.0,
currentValue;
// Find if we have an ending of .0, and backtrack.
if (floatingPointString[stringLength - 1] == '0' && floatingPointString[stringLength - 2] == '.')
index = stringLength - 3;
else
index = stringLength - 1;
for (; index > 0; --index)
{
if (floatingPointString[index] == '.')
--index;
// Subtract ASCII '0' converts ASCII to integer.
currentValue = (double) floatingPointString[index] - '0';
returnValue += (long) currentValue * pow (10.0, powerOfTen);
powerOfTen += 1.0;
}
if (floatingPointString[0] == '-')
returnValue *= -1;
return returnValue;
}
回答5:
The integer equivalent of a float
number f
float f=123.456;
can be made using modff() like
float integral, fractional;
char str[50], temp[20];
fractional = modff(f, &integral);
Now integral
has the integer part (like 123.000000) and fractional
has the fractional part (like 0.456000).
If the floating point number (f
in this case) were negative, both integral
and fractional
would be negative.
You can do
if(fractional<0)
{
fractional = -fractional;
}
to remedy that.
Now,
sprintf(temp, "%g", fractional);
The %g
format specifier will remove the trailing zeros and temp
will now have "0.456"
.
sprintf(str, "%g%s", integral, temp[1]=='.'?temp+2:"");
The temp[1]=='.'?
is done because if the fractional part were 0
, there would'v been no decimal point while printing fractional
as it would've been 0
and not 0.000000
. If the second character in temp
is not .
, fractional
is zero and we needn't bother with it.
Now in our case, str
would be "123456"
. But that's in the form of a string. We need to convert it into an integer. Use strtol()
for that.
long l=strtol(str, NULL, 10);
if(l>INT_MAX || errno==ERANGE)
{
printf("\noverflow");
}
else
{
printf("\n%d", strtol(str, NULL, 10));
}
You may check the return value of strtol()
and that of errno
(from errno.h
. Check whether it is ERANGE
) to see if overflow occurred.
To see if the resultant value can be stored in an int
, first store the value returned by strtol()
in a long int
and see if that is greater than INT_MAX
(it's in limits.h
).
It should be noted that the accuracy of the result will depend upon the accuracy with which the floating point number is represented in binary.
回答6:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f2i(float v, int size, int fsize){
char *buff, *p;
int ret;
buff = malloc(sizeof(char)*(size + 2));
sprintf(buff, "%*.*f", size, fsize, v);
p = strchr(buff, '.');
while(*p=*(p+1))p++;
ret = atoi(buff);
free(buff);
return ret;
}
int main(){
float f = 123.3443;
printf("%d\n", f2i(f, 7, 4));
f=123.542;
printf("%d\n", f2i(f, 6, 3));
return 0;
}
来源:https://stackoverflow.com/questions/9644327/how-to-convert-floating-value-to-integer-with-exact-precision-like-123-3443-to-1