在一些运算中需要判断两个浮点数之间是否成倍数关系,不知如何进行判断,double q = dPrice / dMinProce;double e = min(q - (int)q, (int)q + 1 - q);然后判断e是否足够小;或是把两个浮点数相除的结果转成字元型然后判断是否为整数。我只能想到这两种方法了,还请各位大神赐教。


如果目的是比较两个小数之间是否成倍数关系就不要用浮点类型来保存小数,浮点在保存小数的过程中有很大的可能会损失精度。C#里面可以用decimal保存小数,没有精度损失,然后判断余数是否为0。

这件事情还是能做的而且也不难。能用浮点精确表示的数字,也能精确地得到计算结果。

IEEE754的浮点是这样的结构(这里只讨论Normal样式的浮点数,subnormal的类似就不展开了):

[公式]

以双精度浮点为例就是这样:

[公式]假设我们要求浮点数[公式]是不是能被[公式]整除,就可以这么干:先取出浮点数[公式]的小数部分,按bit转成一个整数[公式],第53位设为1,就是说[公式]然后bit把[公式]的幂部转成整数[公式],有[公式]同理,[公式]

不需要考虑符号位,所以

[公式]

到这里就比较好做了,先处理[公式],找到一个足够大的[公式],使

[公式], 其中[公式]为整数([公式]说得直观点就是[公式]从最低位0开始数0的个数)有[公式]这里就很直观了,不过要分情况看:[公式][公式]都是低于[公式]的整数,
  1. 直接用整数计算,如果[公式]不能整除,则[公式]一定不能整除
  2. 如果[公式]能整除,设[公式],则

[公式]

同样找足够大的[公式]使[公式],有

[公式][公式],则[公式]能整除,否则不能整除(结果是个小数)。不过这应该就是计算机浮点除法的做法,所以一般地直接相除然后判断结果是不是整数就行了。

这问题在微指令级别还有讨论价值,排除0操作数后先比阶数,不能否定的话尾数做位移

高级语言你直接除就好了

更新:

或许也可以用二分法,令较小的那个数不断地加上它自己,看什么时候能够等于或超过较大的那个数。--------------------------------------------------

我也觉得用字元串进行高精度(或任意精度)表示是唯一的办法。

考虑浮点数的IEEE-754表示方法,有部分比较大的整数是无法精确表示的,那也就意味著连两个浮点数之间的"倍数关系"这个数据本身都无法精确表示。

而整除是一个要求绝对精确的概念,不能说a / b = 2.999999就叫整除了,必须严格地有a / b = 3才叫整除。所以我认为只能用字元串表示。

如果你是要简单不严格(能应对绝大多数情况)的实现,那么就是你想的以及各位答主说的。

如果你想要真·严谨,那么你是否确认一定是给定两个内部是二进位的double数据来除,还是给定两个长度不大的十进位字元串(比如你说的金额),是的话就乘10^n转为整数再来。如果是给定了double……(这种情况下已经可能出现十进位小数a.0000000000001了,输入的十进位数已经会有误差,可能造成本来整除的被报不能整除)那我觉得只能手动拆出53位二进位小数,模拟二进位除法,最后根据指数的差以及最后的结果判断到了整数之下是否还有余数。-- 更新 --尝试写了一下真·精确判定,运用一些二进位性质,似乎可以只做一次64位无符号整数除法。

但是……越写越觉得可以直接浮点除,是整除一定会得浮点数能表达的整数……难道是错觉【

#include &
#include &

typedef uint64_t TU;
typedef double TF;

void print64(void* n){
TU* pin=(TU*) n;
int i=64;
while(i--){
putchar((!!((((TU)1)&&>1)-(TU_MASK&>&>12))
#define TF_FRAC_MASK (TU_MASK&>&>12)
#define TF_SIGN_MASK (TU_MASK-(TU_MASK&>&>1))

void TFExtract(TF x,TU* frac, int* exp) {
TU a=*((TU *)x);
a=~TF_SIGN_MASK;
if((aTF_EXP_MASK)==TF_EXP_MASK){
a=TF_FRAC_MASK;
*frac=(TU)0;
*exp=0;
}else if((aTF_EXP_MASK)==(TU)0){
a=TF_FRAC_MASK;
*exp=1;
}else{
*exp=(int)((aTF_EXP_MASK)&>&>TF_FRAC_BIT);
a=TF_FRAC_MASK;
a|=((TU)1)&&>=1;
(*exp)++;
}
*frac=a;
}

int TFIsTimes(TF a,TF b) {
TU fa,fb,ft;
int ea,eb,et;
if(a==0.0||b==0.0){
return 1;
}
TFExtract(a,fa,ea);
TFExtract(b,fb,eb);
printf("%d ",ea);print64(fa);
printf("%d ",eb);print64(fb);
if(ea==0||eb==0){ // either Inf or NaN
return 0;
}
if(fa==fb){
return 1;
}else if(fa&=0;
}

int main(){
TF a,b;
printf("Enter two FP decimal numbers:
");
while(scanf("%lg%lg",a,b)==2){
printf("a=");print64(a);
printf("b=");print64(b);
printf("%s
",TFIsTimes(a,b)?"YES":"NO");
}
return 0;
}


10^n然后强转为整型再整除,前提是需要知道小数的位数
完全整除是不存在的,类似于比较大小在浮点数中比较大小很多时候是允许"偏差值",如if(1.00000001-0.000002&<0.0000001)这样对于整除应该使用"偏差值"处理,允许偏差值的产生
只知道最简单的常规方法,判断a是否能「整除」bboolean judge(double a,double b){

int i=0;

for(;a>0;){a-=b;i++;}if(a!=0){print(「a是b的」+i+「倍,余数是」+(a+b));return false;}else {

print(「a是b的」+i+「倍」);

return true}}

让我想一个:

bitcast转整数,然后取mod。一会儿试验一下。


推荐阅读:
相关文章