How to convert floating value to integer with exact precision like 123.3443 to 1233443?

╄→гoц情女王★ 提交于 2021-02-07 11:56:18

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!