10

Sample code:

int main() {
  float f = 123.542;
  int i = (int)f;
  printf("%d\n",i);
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
sur
  • 345
  • 1
  • 3
  • 13
  • 2
    What if the number is `1.999999999999`? Hint: What you're trying do is not possible. (or at least it's poorly defined with binary floating-point) – Mysticial Mar 10 '12 at 06:05
  • Perhaps what you want is to get as much of a float to the left of some portion which is close to zero (with some tolerance)? – markw Mar 10 '12 at 06:10
  • @Mysticial: It's actually always possible with floating-point, as the FP exponent is a power of 2. The results will just usually not be what you want (e.g, it'll only work for exact binary fractions). –  Mar 10 '12 at 06:18
  • Assuming a 32-bit IEEE float, the exact decimal value of f in your example will be 123.54199981689453125. That is not what would be printed by printf, because it uses a heuristic which prints the shortest representation that, if parsed back to float, would give you the exact same float. I mention this to point out that others are correct that your question might not be well formed enough to provide a good answer. – PeterAllenWebb Sep 19 '15 at 23:51

6 Answers6

10

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);
juergen d
  • 201,996
  • 37
  • 293
  • 362
  • 2
    Not really generally helpful answer (though asker would get exactly what he asked for). It's (very) probably not what he had in mind. – Tomas Pruzina Mar 15 '12 at 17:10
0

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;
}
  • Why answer with C++ code for a C post? Recommend porting to C. – chux - Reinstate Monica Sep 22 '15 at 13:51
  • `4 + FLT_MANT_DIG - FLT_MIN_EXP` is too small. See [comment](http://stackoverflow.com/questions/9644327/how-to-convert-floating-value-to-integer-with-exact-precision-like-123-3443-to-1#comment53280321_32674012) – chux - Reinstate Monica Sep 22 '15 at 14:03
  • `"\%%if"` invalid escape sequence. – chux - Reinstate Monica Sep 22 '15 at 14:04
  • 1) With `int index; ... if (floatingPointString[index - 1]`, index is not initialized. 2) The algorithm has some promise,yet is has to many errors. Suggest review, test and re-post. – chux - Reinstate Monica Sep 22 '15 at 14:08
  • I see what you were saying. I fixed the errors but the code is not debugged. The max size of the string is correct. This is for a 32-bit float. Replace FLT with DBL and float to double and it will work correctly. See the following Stack Overflow post for max size of float: http://stackoverflow.com/questions/1701055/what-is-the-maximum-length-in-chars-needed-to-represent-any-double-value –  Sep 27 '15 at 00:29
0

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.

J...S
  • 5,079
  • 1
  • 20
  • 35
0

Multiply the float by 10^x where x is how many digits after the decimal you want and then cast to int.

gliderkite
  • 8,828
  • 6
  • 44
  • 80
markw
  • 620
  • 3
  • 14
-1
#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;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70