2012-06-26 41 views
16

我想圓一個浮點數給定精度,例如:回合浮動給定精度

0.051 i want to convert it to 
0.1 

0.049 i want to convert it to 
0.0 

0.56 i want to convert it to 
0.6 

0.54 i want to convert it to 
0.5 

我不能更好地解釋,但這樣做的原因是把一個點位置(如0.131f,0.432f)到網格中的瓦片位置(如0.1f,0.4f)。

有什麼辦法可以達到這個目的嗎?

+0

可能重複的[如何在C++中整數(自然)舍入?](http://stackoverflow.com/questions/5834368/how對於整數自然在c) –

+0

將浮點數舍入到1或更多的小數位沒有多大意義;像'0.1'這樣的數字不能完全用二進制浮點表示。舍入可以在輸出上完成(對一個字符串或一個文件)。 –

+0

我們在IT部門,我們試圖用代碼行代表真實世界的無限可能性,這裏的一切都很有意義。我在遊戲中使用無限滾動背景,失去精度並不重要。 – SteveL

回答

21

只要你的網格是規則的,只要找到一個從整數到這個網格的轉換。因此,讓我們說你的網格是

0.2 0.4 0.6 ... 

然後你一輪

float round(float f) 
{ 
    return floor(f * 5 + 0.5)/5; 
    // return std::round(f * 5)/5; // C++11 
} 
+1

謝謝你,這很簡單,它的作品完美! – SteveL

+0

似乎無法正常工作。 0.5被轉換爲0.6。 – Niki

+1

@Niki ......這就是你所期望的,不是嗎? – marton78

7

標準ceil()floor()函數沒有一個精確的,我想可以解決,通過增加自己的精度 - 但這可能引入錯誤 - 例如

double ceil(double v, int p) 
{ 
    v *= pow(10, p); 
    v = ceil(v); 
    v /= pow(10, p); 
} 

我想你可以測試看看這對你是否可靠?

+0

是不是/ = pow(10,p)OR * = pow (10,-p)? –

+0

@AurélienOoms,謝謝,小錯字... – Nim

3

使用floor()ceil()floor會漂浮轉換爲下一個較小的整數,ceil下一個更高:

floor(4.5); // returns 4.0 
ceil(4.5); // returns 5.0 

我認爲下面將工作:

float round(float f) 
{ 
    return floor((f * 10) + 0.5)/10; 
} 

floor(f + 0.5)將舍爲整數。首先乘以10,然後除以10,結果乘以0.1即可。

+0

負浮動怎麼樣? (我曾經在更好的std lib覆蓋之前使用它來獲得正浮點數。) – sage

5

的算法可以使用:

  • 拿到10到的功率(數的-顯著位)(= P10)
  • 由P10
  • 乘以你的雙重價值添加:0.5(或者負減 - 見Ankush沙阿的評論)
  • 除以(P10)這筆錢的整數部分 - 答案是你的圓角數
+2

小點:如果數字是負數,則必須減去0.5 –

5

ED IT 1:我一直在尋找python的numpy解決方案,並沒有意識到OP要求C++哈哈,哦。

編輯2:哈哈,看起來我甚至沒有解決您的原始問題。它看起來像你真的想按照十進制整數(操作與給定數字無關),而不是精確度(操作取決於數字),其他操作已經解決了這個問題。

我實際上也在尋找這個,但找不到東西,所以我把numpy數組的實現放在一起。看起來它實施了slashmais所說的邏輯。

def pround(x, precision = 5): 
    temp = array(x) 
    ignore = (temp == 0.) 
    use = logical_not(ignore) 
    ex = floor(log10(abs(temp[use]))) - precision + 1 
    div = 10**ex 
    temp[use] = floor(temp[use]/div + 0.5) * div 
    return temp 

這裏是一個C++標版本,以及,你可能會做同樣的事情上面使用艾根(他們有邏輯索引):(我也把這個作爲一個機會練習一些提振哈哈):

#include <cmath> 
#include <iostream> 
#include <vector> 
#include <boost/foreach.hpp> 
#include <boost/function.hpp> 
#include <boost/bind.hpp> 

using namespace std; 

double pround(double x, int precision) 
{ 
    if (x == 0.) 
     return x; 
    int ex = floor(log10(abs(x))) - precision + 1; 
    double div = pow(10, ex); 
    return floor(x/div + 0.5) * div; 
} 

    template<typename T> 
vector<T>& operator<<(vector<T> &x, const T &item) 
{ 
    x.push_back(item); 
    return x; 
} 

int main() 
{ 
    vector<double> list; 
    list << 0.051 << 0.049 << 0.56 << 0.54; 
    // What the OP was wanting 
    BOOST_FOREACH(double x, list) 
    { 
     cout << floor(x * 10 + 0.5)/10 << "\n"; 
    } 

    cout << "\n"; 

    BOOST_FOREACH(double x, list) 
    { 
     cout << pround(x, 0) << "\n"; 
    } 

    cout << "\n"; 

    boost::function<double(double)> rounder = boost::bind(&pround, _1, 3); 
    vector<double> newList; 
    newList << 1.2345 << 1034324.23 << 0.0092320985; 
    BOOST_FOREACH(double x, newList) 
    { 
     cout << rounder(x) << "\n"; 
    } 

    return 0; 
} 

輸出:

0.1 
0 
0.6 
0.5 

0.1 
0 
1 
1 

1.23 
1.03e+06 
0.00923 
0

由於鳴叫鴨編輯我的問題,並刪除了代碼說問題不應該包含答案(可以理解),我會在這裏寫的解決方案:

float round(float f,float prec) 
{ 
    return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec)); 
} 
2

通常你知道編譯時所需的精度。因此,使用模板戰俘功能可用here,你可以這樣做:

template <int PRECISION> 
float roundP(float f) 
{ 
    const int temp = Pow<10,PRECISION>::result; 
    return roundf(f*temp)/temp; 
} 

int main() { 
    std::cout << std::setprecision(10); 
    std::cout << roundP<0>(M_PI) << std::endl; 
    std::cout << roundP<1>(M_PI) << std::endl; 
    std::cout << roundP<2>(M_PI) << std::endl; 
    std::cout << roundP<3>(M_PI) << std::endl; 
    std::cout << roundP<4>(M_PI) << std::endl; 
    std::cout << roundP<5>(M_PI) << std::endl; 
    std::cout << roundP<6>(M_PI) << std::endl; 
    std::cout << roundP<7>(M_PI) << std::endl; 
} 

測試here

結果還顯示瞭如何不精確是浮點表示:)

3.099999905

3.140000105

3.14199996

3.141599894

3.141590118

3.141592979

3.141592741

可以使用雙有更好的效果:

template <int PRECISION> 
double roundP(double f) 
{ 
    const int temp = Pow<10,PRECISION>::result; 
    return round(f*temp)/temp; 
} 

印刷精度20:

3.1000000000000000888

3.1400000000000001243

3.1419999999999999041

3.1415999999999999481

3.1415899999999998826

3.1415929999999998579

3。1415926999999999047

0

算法取整浮點數:

double Rounding(double src, int precision) { 
     int_64 des; 
     double tmp; 
     double result; 
     tmp = src * pow(10, precision); 
     if(tmp < 0) {//negative double 
      des = (int_64)(tmp - 0.5); 
     }else { 
      des = (int_64)(tmp + 0.5); 
     } 
     result = (double)((double)dst * pow(10, -precision)); 
     return result; 
    } 
1

我將簡要地優化在最後幾個答案,輸入數字轉換爲雙第一,以防止溢出。示例函數(不太漂亮,但工作得很好):

#include <cmath> 

// round float to n decimals precision 
float round_n (float num, int dec) 
{ 
    double m = (num < 0.0) ? -1.0 : 1.0; // check if input is negative 
    double pwr = pow(10, dec); 
    return float(floor((double)num * m * pwr + 0.5)/pwr) * m; 
}