web-dev-qa-db-ja.com

123.3443から1233443のような正確な精度で浮動値を整数に変換する方法は?

サンプルコード:

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

123.3443は、浮動小数点数で正確に表すことはできません。32ビットの浮動小数点数では、実際には16166984 / 131072として表されます。これは、実際には123.3443ではなく123.34429931640625です。 (約6.8 x 10 ^ -7だけずれています。)

これが本当に望ましい結果である場合(おそらくそうではないでしょう)、IEEE-754 floatがどのように機能するかを確認し、お気に入りの任意精度の数学スイートを引き出します。 「舞台裏」で何が起こっているのかを理解したら、正確な表現を生成することはtoo難しいことではありません。 「十分に近い」丸められた表現を生成することは、実際にははるかに困難です。 :)

10
duskwuff
int i = (int) (f * 10000 + 0.5);
2
juergen d

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)が負の場合、integralfractionalの両方が負になります。

できるよ

_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_の場合、_0_ではなく_0.000000_であったため、fractionalを出力するときに小数点がなかったためです。 tempの2番目の文字が_._でない場合、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_)。

結果の精度は、浮動小数点数が2進数で表される精度に依存することに注意してください。

0
J...S

float10^xを乗算します。ここで、xは、小数の後の桁数で、intにキャストします。

0
markw

変換された数値を繰り返し処理する必要がなく、数値を整数に変換することのみを目的としている場合、最も簡単な方法は、sprintfを使用し、10のべき乗のルールを使用してforループで小数を合計することです。数学に「正確な精度」が必要な場合は、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
user2356685