计算器开发遇到精度问题,请指导我

深_SHEN 2013-01-25 10:58:27
很简单的问题,
tan(arcsin(sqrt(2.0)/2.0))-1.0
很显然,2分之根2求arcsin就是45度,求tan自然是1.0

但对计算机,就不那么简单了。
计算机得到的tan的结果是1.0000000000000002
1和0总数是16位。

但减1后,结果是2.2...×10^-16显然不是0。
我不敢冒然去掉不可靠的位,因为怕影响后续计算。

据我分析,这是因为减1后,计算机把不可靠的0后的2,当作了有效数字。所以导致了上述结果。
那我怎么办才好呢。
...全文
861 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2013-04-28
  • 打赏
  • 举报
回复
引用 35 楼 sz3602 的回复:
[quote=引用 33 楼 lm_whales 的回复:] 如果计算不够精确,就开高精度计算吧;如果足够了,就用内部类型计算! 这个没有必要纠结。看实际应用的需要就可以了!
引用 34 楼 lm_whales 的回复:
比如Windows XP提供的计算器,应该是高精度计算,浮点数计算精度是不够的。 可以自定义128 位,256位整数,浮点数然后计算精度就自然够了!
和精度无关,我只想显示的时候能正确显示即可[/quote] 这个恰恰和精度有关系,如果表示不精确很多时候,是不可能显示精确的。 而什么时候表示精确和浮点数结构有关系,有些可以精确表示,显示没有问题。 有些虽然表示不十分精确,也可以正确显示。 但是要想所有数都正确显示,有点困难。 另外浮点数要正确显示必须必须在表示极限以内。 比如 15 为 精度表示极限,那就用13位,12位,可以大致精确显示出来但是不能保证,一定不会出现不精确的情况。 如果用高精度计算,还是可以以任意精度,精确表示的。
深_SHEN 2013-04-12
  • 打赏
  • 举报
回复
引用 33 楼 lm_whales 的回复:
如果计算不够精确,就开高精度计算吧;如果足够了,就用内部类型计算! 这个没有必要纠结。看实际应用的需要就可以了!
引用 34 楼 lm_whales 的回复:
比如Windows XP提供的计算器,应该是高精度计算,浮点数计算精度是不够的。 可以自定义128 位,256位整数,浮点数然后计算精度就自然够了!
和精度无关,我只想显示的时候能正确显示即可
haierpro 2013-04-12
  • 打赏
  • 举报
回复
其实现实中也就只有2楼的做法,让显示结果的精度比计算精度低就行了。 至于怎么降低显示精度,了解一下float类型的内存格式,有效数部分取出来做取舍,指数部分不动就可以了。 比如1.0000000000000002,这里有效位有17位,可以只取10位(位数也随便定,只要比16小就行了),四舍五入法和舍去法都可以。 再比如1.23456x10^-50,这里有效数字是1.23456,总长度才6位,完全在输出精度范围内,不用就不用做近似了。
lm_whales 2013-04-07
  • 打赏
  • 举报
回复
比如Windows XP提供的计算器,应该是高精度计算,浮点数计算精度是不够的。 可以自定义128 位,256位整数,浮点数然后计算精度就自然够了!
lm_whales 2013-04-07
  • 打赏
  • 举报
回复
如果计算不够精确,就开高精度计算吧;如果足够了,就用内部类型计算! 这个没有必要纠结。看实际应用的需要就可以了!
深_SHEN 2013-03-30
  • 打赏
  • 举报
回复
问题仍未解决, double d; d= 5.2 * pow(10.0, -50) * tan(asin(sqrt(2.0)/2.0)); if (d<DBL_EPSILON) printf("zero!\n"); else printf("non-zero!\n"); 结果不幸,是zero,应该是non-zero,要注意到5.2e-50是一个用户输入的数字,并且在数学上5.2是有效的数字,但是此处被程序误认为0,很不幸; double d; d= tan(asin(sqrt(2.0)/2.0)) - 1.0; if (d<DBL_EPSILON) printf("zero!\n"); else printf("non-zero!\n"); 结果不幸,是non-zero,但理论上d应该严格是0,会导致显示问题很不幸; double d; d= tan(asin(sqrt(2.0)/2.0)) - 1.0; if (d<=DBL_EPSILON) printf("zero!\n"); else printf("non-zero!\n"); 预料之内是zero,因为从调试器中看到,d==DBL_EPSILON是真; 故在第一种情况下,只用<DBL_EPSILON是万万不行的。 所以通过大家讨论,还是无法看出计算结果是否为0。
赵4老师 2013-03-28
  • 打赏
  • 举报
回复
对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
mujiok2003 2013-03-28
  • 打赏
  • 举报
回复
1. 函数Sin等已经引入了误差,除非你自己实现,否则你要得到精确值是办不到的。 2. 浮点数可以直接和0比较,没有问题。 double a; a = 0; 0 == a;//true a = 1e-19; 0 == a;//false
baichi4141 2013-03-28
  • 打赏
  • 举报
回复
顺便说一下,windows自带的计算器没有楼主想要的这个美化功能,tan(45)-1显示出来的结果不是0 大概是因为在微软看来,精确比美观更重要吧
baichi4141 2013-03-28
  • 打赏
  • 举报
回复
1.000000000000000和1.0000000000000002,计算机分不出来这两个数之间有什么区别。当然,人肉眼可以判断,前者后面一串0,后者一串0后面跟个2,不自然,但自然不自然跟对不对没关系 3.12354234254242432和3.12354234254242433,哪个更自然?哪个更正确?你看数值本身看不出来。要精确,就只能算出多少是多少,你任何“让这个数值看起来更自然”的行为,都是在增大误差 根据浮点数的表示方式,用浮点数来表示1.46823×10-50这个数不可能是精确的,如果楼主以为这个数是精确地,那只能说楼主根本就没弄懂浮点数是什么东西 你看这个数的十进制表示后面部分全是0,计算机里用于存储它的二进制可不是一堆0,所以1.46823×10-50跟1.468230000001×10-50,计算机根本不可能区分它们 要像人肉眼一样区分,那只能把两个数都按十进制打印成字符串,然后看哪边一堆0——这是为了美观而进行的字符串处理,而不是数学上的精确计算 楼主想要的功能,只能通过字符串处理实现 先在内存中打印成字符串,然后遍历每一个字符,看哪个字符串后面一堆0,就选择这个字符串去掉0后显示出来
yhuib 2013-03-28
  • 打赏
  • 举报
回复
你得确定你的系统有效位数是多少位,每步都只处理和显示相应的位数,超过部分四舍五入
深_SHEN 2013-03-25
  • 打赏
  • 举报
回复
引用 25 楼 zhao4zhong1 的回复:
引用 24 楼 sz3602 的回复:引用 23 楼 zhao4zhong1 的回复:结合16楼理解15楼,还是理解不了,请在百度搜“浮点表示法”。 您好,我看了浮点表示法,但是感觉和我的问题没有关系,可能我还没有理解您的意思。 我知道不能用浮点数精确表示一个数字,我想要的就只是计算出tan(arcsin(sqrt(2.0)/2.0))-1.0=0.0即可。 有办法……
感谢您的回答,但是有这样一个问题: Ans = tan(arcsin(sqrt(2.0)/2.0))*5.3*10^-20这个数的结果是Ans = 5.3*10^-20而非零,所以用 if (fabs(Ans)<DBL_EPSILON) 判断是不行的。
深_SHEN 2013-03-01
  • 打赏
  • 举报
回复
引用 23 楼 zhao4zhong1 的回复:
结合16楼理解15楼,还是理解不了,请在百度搜“浮点表示法”。
您好,我看了浮点表示法,但是感觉和我的问题没有关系,可能我还没有理解您的意思。 我知道不能用浮点数精确表示一个数字,我想要的就只是计算出tan(arcsin(sqrt(2.0)/2.0))-1.0=0.0即可。 有办法吗? 判断结果是否小于DBL_EPSILON而人为置0.0是不行的。因为例如1.23456x10^-50虽然小于DBL_EPSILON,但它不等于0.0
赵4老师 2013-03-01
  • 打赏
  • 举报
回复
引用 24 楼 sz3602 的回复:
引用 23 楼 zhao4zhong1 的回复:结合16楼理解15楼,还是理解不了,请在百度搜“浮点表示法”。 您好,我看了浮点表示法,但是感觉和我的问题没有关系,可能我还没有理解您的意思。 我知道不能用浮点数精确表示一个数字,我想要的就只是计算出tan(arcsin(sqrt(2.0)/2.0))-1.0=0.0即可。 有办法吗? 判断结果是否小于DBL_E……
#include <stdio.h>
#include <math.h>
#include <float.h>
int main() {
    double d;

    d=tan(asin(sqrt(2.0)/2.0))-1.0;
    printf("tan(arcsin(sqrt(2.0)/2.0))-1.0=%3.1lf\n",d);
    if (fabs(d)<DBL_EPSILON) {
        printf("OK.\n");
    } else {
        printf("Error!\n");
    }
    return 0;
}
//tan(arcsin(sqrt(2.0)/2.0))-1.0=0.0
//OK.
赵4老师 2013-02-04
  • 打赏
  • 举报
回复
结合16楼理解15楼,还是理解不了,请在百度搜“浮点表示法”。
深_SHEN 2013-02-03
  • 打赏
  • 举报
回复
引用 15 楼 zhao4zhong1 的回复:
include\float.h C/C++ code?12345678910111213...#define DBL_DIG 15 /* # of decimal digits of precision */#define DBL_EPSILON 2.2204460492503131e-016 /* sm……
我还是没懂。能再说清楚一点吗
深_SHEN 2013-01-31
  • 打赏
  • 举报
回复
没有办法吗??
赵4老师 2013-01-29
  • 打赏
  • 举报
回复
15楼正解!
深_SHEN 2013-01-29
  • 打赏
  • 举报
回复
其实有误差不怕,我就是想显示的时候不显示误差。 减法能改变有效数字个数,例如本帖的例子。由于有效数位改变了,所以出现了错误。 我不在意计算是否有误差。
深_SHEN 2013-01-29
  • 打赏
  • 举报
回复
引用 19 楼 zhao4zhong1 的回复:
15楼正解!
请问怎么正解了?我都说了,1.23456x10^-50都是准确的。我没明白怎么就正解了?
加载更多回复(17)

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧