2010-03-22 51 views
12

我想檢查浮點值是否「接近」是32的倍數。 64.1「幾乎」被32整除,63.9也是如此。「幾乎可以整除」

現在我這樣做:

#define NEARLY_DIVISIBLE 0.1f 
float offset = fmodf(val, 32.0f) ; 
if(offset < NEARLY_DIVISIBLE) 
{ 
    // its near from above 
} 
// if it was 63.9, then the remainder would be large, so add some then and check again 
else if(fmodf(val + 2*NEARLY_DIVISIBLE, 32.0f) < NEARLY_DIVISIBLE) 
{ 
    // its near from below 
} 

有一個更好的方式來做到這一點?

回答

3

好吧,你可以通過減去32次一次從下面獲得mod來切出第二個fmodf。

if(offset < NEARLY_DIVISIBLE) 
    { 
     // it's near from above 
    } 
    else if(offset-32.0f>-1*NEARLY_DIVISIBLE) 
    { 
     // it's near from below 
    } 
+0

+1這是一個非常合理的解決方案,如果你沒有剩餘的功能可用。 – 2010-03-22 05:27:49

+2

或:else if(32.0f - offset quinmars 2010-03-22 10:24:06

2

在一個符合標準的C語言實現,一個將使用remainder函數,而不是fmod

#define NEARLY_DIVISIBLE 0.1f 
float offset = remainderf(val, 32.0f); 
if (fabsf(offset) < NEARLY_DIVISIBLE) { 
    // Stuff 
} 

如果一個人在不符合規範的平臺(MSVC++,例如),然後remainder不幸的是,這是不可用的。我認爲在這種情況下fastmultiplication的答案是相當合理的。

+0

酷,但是,我沒有http://www.digitalmars.com/rtl/fltpnt.html#remainder在MSVC++。 。 ? – bobobobo 2010-03-22 04:41:18

+1

'remaining'已經在C標準中使用了10年,並且在IEEE-754標準中使用了25年。 MSVC是否真的不提供它?您可以從問題中刪除'C'標記,因爲MSVC++不是C編譯器=) – 2010-03-22 04:45:20

+0

@Stephen'fmodf'等效於MSC++中的提示(http://msdn.microsoft.com/en-us/ library/20dckbeh(VS.71).aspx) – 2010-03-22 05:01:27

0

對於我收集你想要檢測的數字是否可以被其他整除,對嗎?

我會做這樣的事情:

#define NEARLY_DIVISIBLE 0.1f 

bool IsNearlyDivisible(float n1, float n2) 
{ 
    float remainder = (fmodf(n1, n2)/n2); 
    remainder = remainder < 0f ? -remainder : remainder; 
    remainder = remainder > 0.5f ? 1 - remainder : remainder; 
    return (remainder <= NEARLY_DIVISIBLE); 
} 
+0

你的代碼對待* NEARLY \ _DIVISIBLE *作爲百分比,而它是OP的絕對值。你爲什麼乘以負數而不是使用「-remainder」? – 2010-03-22 05:51:01

+0

oops ...固定!謝謝! – 2010-03-22 05:58:06

0

我認爲這是正確的:

bool nearlyDivisible(float num,float div){ 
float f = num % div; 
if(f>div/2.0f){ 
f=f-div; 
} 
f=f>0?f:0.0f-f; 
return f<0.1f; 
} 
+0

這個問題沒有什麼是Java;在問題中的代碼是C. – 2010-03-22 05:49:10

+0

我感到沮喪,我確信它是java:O – 2010-03-22 05:49:51

2

你提到,你必須測試近可分與。下面的理論研究應針對的兩個大國近可分測試成立:

#define THRESHOLD 0.11 
int nearly_divisible(float f) { 
    // printf(" %f\n", (a - (float)((long) a))); 
    register long l1, l2; 
    l1 = (long) (f + THRESHOLD); 
    l2 = (long) f; 
    return !(l1 & 31) && (l2 & 31 ? 1 : f - (float) l2 <= THRESHOLD); 
} 

我們正在做的是強迫浮動,和float +閾值長。

f  (long) f (long) (f + THRESHOLD) 
63.9 63   64 
64  64   64 
64.1 64   64 

現在我們測試,如果(長)f是整除與32只要勾選低五位,如果它們都設置爲零,數量是32整除這導致了一系列的誤報:64.2到64.8,當轉換成long時,也是64,並且會通過第一次測試。因此,我們檢查它們的截斷形式和f之間的差異是否小於或等於THRESHOLD。

這也有一個問題:f - (float)l < = THRESHOLD對於64和64.1將適用,但不適用於63.9。因此,我們爲小於64的數字添加了一個例外(當THRESHOLD增加並隨後被強制延長時 - 請注意,正在討論的測試必須包含第一個測試 - 可以被32整除),方法是指定低5位不爲零。這將適用於63(1000000 - 1 == 1 )。

這三個測試的組合將指示數字是否可以被32整除。我希望這很清楚,請原諒我奇怪的英語。

我只是測試可擴展到三個其他大國 - 383.5和388.4之間的下列程序打印數字是整除128

#include <stdio.h> 

#define THRESHOLD 0.11 

int main(void) { 
    int nearly_divisible(float); 
    int i; 
    float f = 383.5; 
    for (i=0; i<50; i++) { 
     printf("%6.1f %s\n", f, (nearly_divisible(f) ? "true" : "false")); 
     f += 0.1; 
    } 
    return 0; 
} 

int nearly_divisible(float f) { 
    // printf(" %f\n", (a - (float)((long) a))); 
    register long l1, l2; 
    l1 = (long) (f + THRESHOLD); 
    l2 = (long) f; 
    return !(l1 & 127) && (l2 & 127 ? 1 : f - (float) l2 <= THRESHOLD); 
} 

似乎好工作至今!

0

你爲什麼不把它除以32,然後取整數和實際結果的差值?

喜歡的東西(原諒未經測試/僞代碼,沒有時間去查找):

#define NEARLY_DIVISIBLE 0.1f 
float result = val/32.0f; 
float nearest_int = nearbyintf(result); 
float difference = abs(result - nearest_int); 
if(difference < NEARLY_DIVISIBLE) 
{ 
    // It's nearly divisible 
} 

如果仍想做的事從上面和下面的檢查,你可以刪除ABS,並檢查是否差異是> 0或< 0.

0

這是沒有使用fmodf兩次。

int main(void) 
{ 
    #define NEARLY_DIVISIBLE 0.1f 
    #define DIVISOR 32.0f 
    #define ARRAY_SIZE 4 
    double test_var1[ARRAY_SIZE] = {63.9,64.1,65,63.8}; 
    int i = 54; 
    double rest; 
    for(i=0;i<ARRAY_SIZE;i++) 
    { 
     rest = fmod(test_var1[i] ,DIVISOR); 
     if(rest < NEARLY_DIVISIBLE) 
     { 
      printf("Number %f max %f larger than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR); 
     } 
     else if(-(rest-DIVISOR) < NEARLY_DIVISIBLE) 
     { 
      printf("Number %f max %f less than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR); 
     } 
    } 
    return 0; 
} 
相關問題