在一些運算中需要判斷兩個浮點數之間是否成倍數關係,不知如何進行判斷,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。一會兒試驗一下。


推薦閱讀:
相關文章