这种题目常规的写法是:
- /*
- 计算多项式3x^3-5x^2+3x+6 的值,设x=1.23。
- 结果和笔算一样么?
- 如果希望和笔算结果完全一致,你会怎样写代码。
- */
- #include <stdio.h>
- #include <stdlib.h>
- #define X 1.23
- int main( void )
- {
- printf( "%f\n",
- ( ( 3. * X - 5. ) * X + 3. ) * X + 6.
- );
-
- system("PAUSE");
- return 0;
- }
程序运行结果为:
7.708101
请按任意键继续. . .
这个结果与手算的结果一致。然而这种“一致”并不是什么好事情,因为它常常会使新手对浮点运算产生误解,误认为浮点运算和整数运算同样是精确的。其实,在前面的代码中,如果令转换说明的精度更高些,譬如
- printf( "%.16f\n",
- ( ( 3. * X - 5. ) * X + 3. ) * X + 6.
- );
就会发现输出结果并非是完全精确的。(输出:7.7081010000000001)
这是因为浮点运算和整数运算有着本质的区别。
首先,浮点类型的数据只是对实数的一种近似表示而非精确表示。在代码中写1.23的时候,在内存中其对应的二进制形式的机器数只是1.23的一个近似值。如果熟悉二进制,那么就会知道1.23根本不可能表示为有限长度的二进制形式,然而在计算机内部每一种数据类型的长度都是确定的,因此1.23只可能以近似的方式存储。
由于这种近似表示的精度很高(float一般有5、6位有效数字,double通常有15、16位有效数字),所以在很多情况下很难察觉其近似性。当然对某些个别数据浮点类型是能精确表示的,但这只是一些特例而非浮点数据的普遍性质。
正是由于这种近似性,浮点数据所能表示的数值的范围比整数类型要宽的多。
显然,本身就是实数的近似表示的浮点数的运算结果也只可能是一个近似值。对此,一定要有非常清醒的认识。
如果希望运算结果和笔算完全一致,必须看到,笔算时,尽管运算时有小数点,但笔算在本质上是按照整数规则运算的。例如
1.23
× 1.23
——————
3 69
24 6
123
——————
151 29
即是整数运算,运算之后在适当的位置添加小数点。
在代码中可以模拟这个计算过程。首先把1.23表示为一个分数123/100,把多项式3x^3-5x^2+3x+6改写为(3(x*100)^3-5(x*100)^2*100+3(x*100)*100^2+6*100^3)/100^3的形式,不难发现此时分子部分是整数运算,在C代码中,整数运算是准确的运算。描述这种算法的代码为:
- #include <stdio.h>
- #include <stdlib.h>
- #define FZ 123 //分子
- #define FM 100 //分母
- int main( void )
- {
- int dxs_fz , dxs_fm ; //多项式分子、分母
-
- dxs_fz = 3 * FZ * FZ * FZ - 5 * FZ * FZ * FM
- + 3 * FZ * FM * FM + 6 * FM * FM * FM ;
- dxs_fm = FM * FM * FM ;
-
- printf( "%d.%06d\n" , dxs_fz / dxs_fm , dxs_fz % dxs_fm );
-
- system("PAUSE");
- return 0;
- }
注意输出时小数部分的转换格式为%06d。
阅读(1690) | 评论(0) | 转发(0) |