浮点数除法取小数部分时 如何避免大long值运算的精度丢失
问题背景
开发过程中需要对极大的64位long类型数值执行除法运算,不需要整数部分结果,仅关注最终得到的小数值。
当前遇到的问题:使用大long值除以较小的64位double类型浮点数时,浮点数需要分配有效位存储整数部分,会导致小数部分精度丢失。
目标实现逻辑:
double x = long_value / double_value % 1;
需求为无论long_value取值多大,都尽可能避免精度损失,寻找运算时可直接丢弃整数部分、不损失浮点数精度的写法。
补充说明:提问者为新注册账号,系统提示you need 15 reputation to cast a vote(需要15点声望值才可投票),暂时无法为提供帮助的回答点赞。
实现方案
核心思路是先取余再做除法,从根源上避免产生量级过大的中间结果,防止整数部分挤占浮点数有效位。
基础double精度实现
直接使用标准库的fmod函数计算余数,再做除法得到小数部分:
#include <math.h> double mod_res = fmod((double)long_value, double_value); double x = mod_res / double_value;
原理说明
- 这个计算逻辑和原本的
long_value / double_value % 1语义完全等价,只是调整了计算顺序规避大中间值带来的精度问题。 fmod((double)long_value, double_value)返回的是long_value除以double_value后的余数,取值范围固定在[0, double_value)区间,数值量级和除数double_value完全一致。后续除以double_value得到的结果落在[0,1)区间,整个计算过程不会出现远大于除数的中间值,double的53位有效位会全部用于小数相关计算,不会出现整数部分挤占有效位导致的精度丢失。
全64位long无精度损失实现
注意64位double只有53位有效尾数,当long_value的绝对值超过2^53时,long转double本身就会存在最低位的精度损失,这是double类型本身的精度限制。如果需要覆盖所有64位long的取值、做到完全无精度损失,可以改用long double类型搭配对应长双精度版本的数学函数计算:
#include <math.h> long double mod_res_ld = fmodl((long double)long_value, (long double)double_value); long double x_ld = mod_res_ld / (long double)double_value; // 最终结果在[0,1)区间,转回double不会丢失精度 double x = (double)x_ld;
这种写法下,long double在x86平台下为80位扩展精度,拥有64位有效尾数,可以完整表示所有64位long类型的整数值,全程不会出现整数转换带来的精度损失。
内容的提问来源于stack exchange,提问作者Ryan Hedgecock
相关产品推荐
相关产品推荐

