2012-06-26 6 views
16

tôi muốn làm tròn một số thập phân với một độ chính xác nhất định, ví dụ:Vòng một phao đến một độ chính xác cho

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 

tôi không thể giải thích nó tốt hơn, nhưng lý do của việc này là để dịch một vị trí điểm (như 0.131f, 0.432f) đến vị trí của ô trong lưới (như 0.1f, 0.4f).

Có cách nào để đạt được điều này không?

+0

có thể trùng lặp của [Làm thế nào để làm tròn thành số nguyên (tự nhiên) trong C++?] (Http://stackoverflow.com/questions/5834368/how -to-round-to-integer-natural-in-c) –

+0

Làm tròn số dấu phẩy động đến 1 hoặc nhiều chữ số thập phân không có ý nghĩa nhiều; một số như '0.1' không thể được biểu diễn chính xác trong dấu phẩy động nhị phân. Làm tròn có thể được thực hiện trên đầu ra (đến một chuỗi hoặc một tập tin). –

+0

Chúng tôi đang ở trong bộ phận CNTT, chúng tôi đang cố gắng để đại diện cho khả năng vô hạn của thế giới thực trong dòng mã, tất cả mọi thứ có ý nghĩa ở đây. Tôi đang sử dụng điều này cho một nền cuộn vô hạn trong một trò chơi, mất độ chính xác không thực sự quan trọng. – SteveL

Trả lời

21

Miễn là lưới của bạn thường xuyên, chỉ cần tìm chuyển đổi từ số nguyên sang lưới này. Vì vậy, chúng ta hãy nói lưới của bạn là

0.2 0.4 0.6 ... 

Sau đó, bạn tròn bởi

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

cảm ơn bạn, điều này là đơn giản và nó hoạt động hoàn hảo !!! – SteveL

+0

Có vẻ như không hoạt động chính xác. 0,5 được chuyển thành 0,6. – Niki

+1

@Niki ... và đó chỉ là những gì bạn mong đợi, phải không? – marton78

7

Chức năng chuẩn ceil(), floor() không có độ chính xác, tôi đoán có thể làm việc xung quanh bằng cách thêm chính xác của riêng bạn - nhưng điều này có thể đưa ra lỗi - ví dụ:

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

Tôi đoán bạn có thể kiểm tra xem điều này có đáng tin cậy cho bạn không?

+0

Không phải là/= pow (10, p) OR * = pow (10, -p)? –

+0

@ AurélienOoms, cảm ơn, một lỗi nhỏ ... – Nim

3

Sử dụng floor()ceil(). floor sẽ chuyển đổi một phao số nguyên nhỏ hơn tiếp theo, và ceil để cao hơn tiếp theo:

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

Tôi nghĩ rằng đây sẽ làm việc:

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

floor(f + 0.5) sẽ tròn đến một số nguyên. Đầu tiên nhân với 10 và sau đó chia kết quả cho 10 bạn làm tròn bằng số gia là 0,1.

+0

Điều gì về phao âm? (Tôi đã từng sử dụng điều này cho các phao dương trước khi phủ sóng lib tốt hơn.) – sage

5

Một thuật toán bạn có thể sử dụng:

  • nhận được 10-to-the-điện (số-of-đáng-chữ số) (= P10)
  • nhân đôi giá trị của bạn bằng cách P10
  • thêm: 0,5 (hoặc trừ nếu tiêu cực - xem bình luận Ankush Shah)
  • chia số nguyên-phần của tổng này bằng cách (P10) - câu trả lời sẽ là số tròn của bạn
+2

điểm nhỏ: nếu số là âm, bạn sẽ phải trừ 0,5 –

5

ED CNTT 1: Tôi đã tìm kiếm các giải pháp cho numpy trong python và không nhận ra rằng OP yêu cầu cho C + + haha, oh well.

CHỈNH SỬA 2: Rất tiếc, có vẻ như tôi thậm chí không giải quyết được câu hỏi ban đầu của bạn. Dường như bạn đang thực sự muốn làm tròn theo một số thập phân (hoạt động độc lập với số đã cho), không phải là độ chính xác (hoạt động phụ thuộc vào số), và những người khác đã giải quyết điều đó.

Tôi thực sự đang tìm kiếm điều này nhưng không thể tìm thấy thứ gì đó, vì vậy tôi đã cùng nhau triển khai thực hiện các mảng có nhiều mảng. Có vẻ như nó thực hiện logic mà slashmais đã nói.

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 

Dưới đây là một phiên bản vô hướng C++ là tốt, và bạn có thể có thể làm điều gì đó tương tự như trên sử dụng Eigen (họ có indexing logic): (Tôi cũng mất này như một cơ hội để thực hành một số tăng hơn haha):

#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; 
} 

Output:

0.1 
0 
0.6 
0.5 

0.1 
0 
1 
1 

1.23 
1.03e+06 
0.00923 
0

Kể từ Mooing Duck sửa câu hỏi của tôi và loại bỏ các mã nói câu hỏi không nên chứa câu trả lời (dễ hiểu), tôi sẽ ghi các giải pháp ở đây:

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

Thông thường bạn biết độ chính xác mong muốn tại thời gian biên dịch. Do đó, bằng cách sử dụng templated Pow chức năng có sẵn here, bạn có thể làm:

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; 
} 

Tested here.

Kết quả cũng cho thấy đại diện điểm cách không chính xác là nổi :)

3,099999905

3,140000105

3,14199996

3,141599894

3,141590118

3,141592979

3,141592741

Bạn có thể có kết quả tốt hơn sử dụng kép:

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

in với độ chính xác 20:

3,1000000000000000888

3,1400000000000001243

3,1419999999999999041

3,1415999999999999481

3,1415899999999998826

3,1415929999999998579

3.1415926999999999047

0

Thuật toán để làm tròn số float:

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

tôi sẽ vắn tắt tối ưu hóa trên vài câu trả lời cuối cùng, chuyển đổi số lượng đầu vào cho một đôi đầu tiên để ngăn chặn tràn. Hàm mẫu (không quá đẹp, nhưng chỉ hoạt động tốt):

#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; 
}