Как преобразовать плавающее значение в целое с точностью до 123,3443 в 1233443? - PullRequest
10 голосов
/ 10 марта 2012

Пример кода:

int main() {
  float f = 123.542;
  int i = (int)f;
  printf("%d\n",i);
}

Ответы [ 6 ]

10 голосов
/ 10 марта 2012

123.3443 не может быть точно представлено числом с плавающей запятой - в 32-разрядном формате с плавающей запятой оно фактически представляется как 16166984 / 131072, что на самом деле составляет 123.34429931640625, а не 123.3443. (Примерно 6,8 х 10 ^ -7.)

Если это действительно тот результат, который вам нужен (а это, вероятно, нет), посмотрите, как работает IEEE-754 с плавающей запятой, и извлеките ваш любимый математический набор произвольной точности. Как только вы поймете, что происходит «за кулисами», генерация точного представления не должна быть слишком сложной. Генерировать «достаточно близкое» округленное представление на самом деле намного сложнее. :)

2 голосов
/ 10 марта 2012
int i = (int) (f * 10000 + 0.5);
0 голосов
/ 20 октября 2017

Целочисленный эквивалент float числа f

float f=123.456;

может быть выполнен с использованием modff() как

float integral, fractional;
char str[50], temp[20];
fractional = modff(f, &integral);

Сейчас integral имеет целочисленную часть (например, 123.000000), а fractional имеет дробную часть (например, 0.456000).

Если число с плавающей запятой (в данном случае f) было отрицательным, оба значения integral и fractional будет отрицательным.

Вы можете сделать

if(fractional<0)
{
    fractional = -fractional;
}

, чтобы исправить это.

Сейчас,

sprintf(temp, "%g", fractional);

Формат %gспецификатор удалит завершающие нули, и temp теперь будет иметь "0.456".

sprintf(str, "%g%s", integral, temp[1]=='.'?temp+2:"");

. temp[1]=='.'? сделано, потому что если бы дробная часть была 0, не было бы десятичной точкипри печати fractional, как это было бы 0, а не 0.000000.Если второй символ в temp не равен ., fractional равен нулю, и нам не нужно беспокоиться об этом.

Теперь в нашем случае str будет "123456".Но это в форме строки.Нам нужно преобразовать его в целое число.Для этого используйте strtol().

long l=strtol(str, NULL, 10);
if(l>INT_MAX || errno==ERANGE)
{
    printf("\noverflow");
}
else
{
    printf("\n%d", strtol(str, NULL, 10));
}

Вы можете проверить возвращаемое значение strtol() и errno (из errno.h. Проверьте, является ли оно ERANGE), чтобы увидеть, переполнено лиПроизошло.

Чтобы увидеть, может ли результирующее значение быть сохранено в int, сначала сохраните значение, возвращенное strtol() в long int, и посмотрите, больше ли оно INT_MAX (оно вlimits.h).

Следует отметить, что точность результата будет зависеть от точности, с которой число с плавающей запятой представлено в двоичном виде.

0 голосов
/ 22 сентября 2015

Если вам не нужно выполнять какую-либо повторяющуюся обработку преобразованного числа и вы хотите преобразовать только числа в целое число, самый простой способ - использовать sprintf, а затем суммировать десятичные числа с помощью цикла for, используя степень10 правил.Если вам нужна «точная точность» для математики, используйте BCD.Следующий алгоритм позволит вам сократить количество цифр для «точной точности».

#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;
}
0 голосов
/ 10 марта 2012
#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;
}
0 голосов
/ 10 марта 2012

Умножьте float на 10^x, где x - это количество цифр после требуемого десятичного знака и затем приведите к int.

...