从 float 创建有理数会给出不精确的结果
Creating rational number from float gives imprecise results
我正在训练我的 C 技能。我正在做一个接收浮点数的函数,并且应该 return 我用 struct 做的一个分数。当我试图将数字四舍五入时,我开始看到一些奇怪的结果。我怀疑这是 floor() 函数中的一些错误。
我使用 Code::Blocks 并且我读到 pow() 函数在使用它时会出现一些错误,所以我认为应该是这样。
我阅读了很多关于 floor() 函数如何工作的资料,但我不知道如何修复它并防止再次产生错误的数字。
我的函数是:
Fraction ftof (float f)
/* Transforms a float in a struct type fraction. */
{
Fraction frac;
int i, decimalPlaces;
float decimalPart, numerator;
decimalPlaces = 0;
printf("Number of decimal places: %d\n", decimalPlaces);
decimalPart = f - floor(f);
printf("Decimal part: %f\n\n", decimalPart);
while (decimalPart != 0)
{
decimalPlaces++;
printf("Houses number updated: %d\n", decimalPlaces);
decimalPart = decimalPart * 10;
decimalPart = decimalPart - floor(decimalPart);
printf("Decimal part updated: %f\n", decimalPart);
}
numerator = f;
frac.denominator = 1;
for (i = 0; i < decimalPlaces; i++)
{
numerator = numerator * 10;
frac.denominator = frac.denominator * 10;
}
frac.numerator = (int) floor(numerator);
writes(frac);
printf("\n");
simplification(&frac);
return frac;
}
我编写的另外两个函数是“写入”和“简化”,它们写入格式化的分数并进行简化,但它们经过了很好的测试并且可以正常工作。
我的主要是:
int main()
{
float decimal;
while (1) {
printf("Type a decimal number: ");
scanf("%f", &decimal);
printf("Typed number: %f\n", decimal);
writes(ftof(decimal));
printf("\n\n");
}
}
通过我放在函数中间的“printf”,它告诉我它正在计算的数字(我从来没有正确理解如何在 CodeBlocks 中调试),所以当我输入 0.25 时,它会结果是 1/4。但是,如果我输入一些更难的数字,比如 0.74,结果会是:
Type a decimal number: 0,74
Typed number: 0,740000
Number of decimal places: 0
Decimal part: 0,740000
Houses number updated: 1
Decimal part updated: 0,400000
Houses number updated: 2
Decimal part updated: 0,000001
Houses number updated: 3
Decimal part updated: 0,000010
Houses number updated: 4
Decimal part updated: 0,000095
Houses number updated: 5
Decimal part updated: 0,000954
Houses number updated: 6
Decimal part updated: 0,009537
Houses number updated: 7
Decimal part updated: 0,095367
Houses number updated: 8
Decimal part updated: 0,953674
Houses number updated: 9
Decimal part updated: 0,536743
Houses number updated: 10
Decimal part updated: 0,367432
Houses number updated: 11
Decimal part updated: 0,674316
Houses number updated: 12
Decimal part updated: 0,743164
Houses number updated: 13
Decimal part updated: 0,431641
Houses number updated: 14
Decimal part updated: 0,316406
Houses number updated: 15
Decimal part updated: 0,164063
Houses number updated: 16
Decimal part updated: 0,640625
Houses number updated: 17
Decimal part updated: 0,406250
Houses number updated: 18
Decimal part updated: 0,062500
Houses number updated: 19
Decimal part updated: 0,625000
Houses number updated: 20
Decimal part updated: 0,250000
Houses number updated: 21
Decimal part updated: 0,500000
Houses number updated: 22
Decimal part updated: 0,000000
0/0
512/311
我的意思是,当只有一位小数时,它确实是 0.4 * 10 = 4,但后来 4 - floor(4) = 0.000001。
我能做什么?
浮点类型通常使用二进制尾数,这意味着可以完全以 10 为基数表示的数字不能完全以 2 为底数表示。像 0.25 这样的数字在二进制中可以精确表示,但 0.4 可以不是。所以你无法得到准确的答案。
解决这个问题的方法不是将数字作为 float
读取,而是作为字符串读取,然后自己执行转换为有理数。
Fraction stof(char *s)
{
Fraction f;
long ipart, fpart;
char *p, *p2;
int i;
p = strchr(s, '.'); // look for the decimal point
ipart = strtol(s, NULL, 10); // get the integer part
if (p) {
fpart = strtol(p+1, &p2, 10); // get the fractional part, saving the end pointer
// to count digits in case of leading zeros
} else {
fpart = 0; // no . found, fractional part is 0
}
printf("ipart=%ld, fpart=%ld\n", ipart, fpart);
f.numerator = ipart; // start with just the integer part
f.denominator = 1;
for (i=0; i<(p2-p-1); i++) { // loop for each digit in the fractional part
f.numerator *= 10; // scale up the numerator and denominator
f.denominator *= 10;
}
f.numerator += fpart; // add in the fractional part
printf("fraction = %ld / %ld\n", f.numerator, f.denominator);
return f;
}
我正在训练我的 C 技能。我正在做一个接收浮点数的函数,并且应该 return 我用 struct 做的一个分数。当我试图将数字四舍五入时,我开始看到一些奇怪的结果。我怀疑这是 floor() 函数中的一些错误。
我使用 Code::Blocks 并且我读到 pow() 函数在使用它时会出现一些错误,所以我认为应该是这样。
我阅读了很多关于 floor() 函数如何工作的资料,但我不知道如何修复它并防止再次产生错误的数字。
我的函数是:
Fraction ftof (float f)
/* Transforms a float in a struct type fraction. */
{
Fraction frac;
int i, decimalPlaces;
float decimalPart, numerator;
decimalPlaces = 0;
printf("Number of decimal places: %d\n", decimalPlaces);
decimalPart = f - floor(f);
printf("Decimal part: %f\n\n", decimalPart);
while (decimalPart != 0)
{
decimalPlaces++;
printf("Houses number updated: %d\n", decimalPlaces);
decimalPart = decimalPart * 10;
decimalPart = decimalPart - floor(decimalPart);
printf("Decimal part updated: %f\n", decimalPart);
}
numerator = f;
frac.denominator = 1;
for (i = 0; i < decimalPlaces; i++)
{
numerator = numerator * 10;
frac.denominator = frac.denominator * 10;
}
frac.numerator = (int) floor(numerator);
writes(frac);
printf("\n");
simplification(&frac);
return frac;
}
我编写的另外两个函数是“写入”和“简化”,它们写入格式化的分数并进行简化,但它们经过了很好的测试并且可以正常工作。
我的主要是:
int main()
{
float decimal;
while (1) {
printf("Type a decimal number: ");
scanf("%f", &decimal);
printf("Typed number: %f\n", decimal);
writes(ftof(decimal));
printf("\n\n");
}
}
通过我放在函数中间的“printf”,它告诉我它正在计算的数字(我从来没有正确理解如何在 CodeBlocks 中调试),所以当我输入 0.25 时,它会结果是 1/4。但是,如果我输入一些更难的数字,比如 0.74,结果会是:
Type a decimal number: 0,74
Typed number: 0,740000
Number of decimal places: 0
Decimal part: 0,740000
Houses number updated: 1
Decimal part updated: 0,400000
Houses number updated: 2
Decimal part updated: 0,000001
Houses number updated: 3
Decimal part updated: 0,000010
Houses number updated: 4
Decimal part updated: 0,000095
Houses number updated: 5
Decimal part updated: 0,000954
Houses number updated: 6
Decimal part updated: 0,009537
Houses number updated: 7
Decimal part updated: 0,095367
Houses number updated: 8
Decimal part updated: 0,953674
Houses number updated: 9
Decimal part updated: 0,536743
Houses number updated: 10
Decimal part updated: 0,367432
Houses number updated: 11
Decimal part updated: 0,674316
Houses number updated: 12
Decimal part updated: 0,743164
Houses number updated: 13
Decimal part updated: 0,431641
Houses number updated: 14
Decimal part updated: 0,316406
Houses number updated: 15
Decimal part updated: 0,164063
Houses number updated: 16
Decimal part updated: 0,640625
Houses number updated: 17
Decimal part updated: 0,406250
Houses number updated: 18
Decimal part updated: 0,062500
Houses number updated: 19
Decimal part updated: 0,625000
Houses number updated: 20
Decimal part updated: 0,250000
Houses number updated: 21
Decimal part updated: 0,500000
Houses number updated: 22
Decimal part updated: 0,000000
0/0
512/311
我的意思是,当只有一位小数时,它确实是 0.4 * 10 = 4,但后来 4 - floor(4) = 0.000001。
我能做什么?
浮点类型通常使用二进制尾数,这意味着可以完全以 10 为基数表示的数字不能完全以 2 为底数表示。像 0.25 这样的数字在二进制中可以精确表示,但 0.4 可以不是。所以你无法得到准确的答案。
解决这个问题的方法不是将数字作为 float
读取,而是作为字符串读取,然后自己执行转换为有理数。
Fraction stof(char *s)
{
Fraction f;
long ipart, fpart;
char *p, *p2;
int i;
p = strchr(s, '.'); // look for the decimal point
ipart = strtol(s, NULL, 10); // get the integer part
if (p) {
fpart = strtol(p+1, &p2, 10); // get the fractional part, saving the end pointer
// to count digits in case of leading zeros
} else {
fpart = 0; // no . found, fractional part is 0
}
printf("ipart=%ld, fpart=%ld\n", ipart, fpart);
f.numerator = ipart; // start with just the integer part
f.denominator = 1;
for (i=0; i<(p2-p-1); i++) { // loop for each digit in the fractional part
f.numerator *= 10; // scale up the numerator and denominator
f.denominator *= 10;
}
f.numerator += fpart; // add in the fractional part
printf("fraction = %ld / %ld\n", f.numerator, f.denominator);
return f;
}