如何设置浮点精度?

时间:2020-04-05 03:48:57

标签: c++

对于a = 1.263839的数字,我们可以做- float a = 1.263839 cout << fixed << setprecision(2) << a <<endl; 输出:-1.26

但是,如果我想设置数字的精度并将其存储,例如- 无需打印即可将1.263839转换为1.26。

5 个答案:

答案 0 :(得分:5)

但是,如果我想设置数字的精度并将其存储

您可以将所需的精度存储在变量中:

int precision = 2;

随后,您可以在将浮点数转换为字符串时使用此存储的精度:

std::cout << std::setprecision(precision) << a;

我认为OP希望在不打印数字的情况下从1.263839转换为1.26。

如果 this 是您的目标,那么您首先必须意识到,最常用的浮点表示法无法表示1.26。可表示的最接近的32位二进制IEEE-754值为1.2599999904632568568359375。

因此,假设采用这种表示形式,那么您可以期望的最好值是非常接近1.26的值。在最佳情况下,我展示了该值,但由于我们需要计算值,因此请记住,除了无法精确表示值之外,还可能涉及一些微小的错误(至少在理论上;使用的示例输入没有错误)下面的算法,但应始终使用浮点数学来考虑精度损失的可能性。

计算如下:

  • 让P赌您要舍入到小数点后的位数(在这种情况下为2)。
  • 让D为10 P (在这种情况下为100)。
  • 将输入乘以D
  • std::round到最接近的整数。
  • 除以D

P.S。有时,您可能不想四舍五入,而想精确到std::floorstd::ceil。这有点棘手。只是std::floor(val * D) / D是错误的。例如,将9.70设置为两位小数,则该数字将变为9.69,这是不希望的。

在这种情况下,您可以执行以下操作:将精度乘以一个大小,四舍五入到最接近的值,然后除以多余的大小并继续:

  • 让P赌您要舍入到小数点后的位数(在这种情况下为2)。
  • 让D为10 P (在这种情况下为100)。
  • 将输入乘以D * 10
  • std::round到最接近的整数。
  • 除以10
  • std::floorstd::ceil
  • 除以D

答案 1 :(得分:1)

您需要截断它。可能最简单的方法是将其乘以一个系数(如果是小数点后2位,则乘以100),然后将其截断或四舍五入,最后除以相同的系数。

现在,请注意,可能会出现浮点精度问题,即使经过这些操作,您的浮点数也可能不是1.26,而是1.26000000000003

答案 2 :(得分:0)

如果您的目标是存储一个小数点后固定位数小的固定数字,则可以通过将其存储为带有隐式十进制乘数的整数来实现:

#include <stdio.h>
#include <math.h>

// Given a floating point value and the number of digits
// after the decimal-point that you want to preserve,
// returns an integer encoding of the value.
int ConvertFloatToFixedPrecision(float floatVal, int numDigitsAfterDecimalPoint)
{
   return (int) roundf(floatVal*powf(10.0f, numDigitsAfterDecimalPoint));
}

// Given an integer encoding of your value (as returned
// by the above function), converts it back into a floating
// point value again.
float ConvertFixedPrecisionBackToFloat(int fixedPrecision, int numDigitsAfterDecimalPoint)
{
   return ((float) fixedPrecision) / powf(10.0f, numDigitsAfterDecimalPoint);
}

int main(int argc, char ** arg)
{
   const float val = 1.263839;

   int fixedTwoDigits = ConvertFloatToFixedPrecision(val, 2);
   printf("fixedTwoDigits=%i\n", fixedTwoDigits);

   float backToFloat = ConvertFixedPrecisionBackToFloat(fixedTwoDigits, 2);
   printf("backToFloat=%f\n", backToFloat);

   return 0;
}

运行时,以上程序将显示以下输出:

fixedTwoDigits=126
backToFloat=1.260000

答案 3 :(得分:0)

如果您要谈论的是将1.26完全存储在变量中,那么您是不可能的(完全可以1.26起作用的机会不大,但是假设它不适合一会儿),因为浮点数不能那样工作。 There are always little inaccuracies是因为计算机处理浮点十进制数字的方式。即使您可以准确获得1.26,也可以在尝试在计算中使用它的那一刻。

也就是说,您可以使用一些数学和截断技巧来使它们变得非常接近:

int main()
{
    // our float
    float a = 1.263839;

    // the precision we're trying to accomplish
    int precision = 100; // 3 decimal places

    // because we're an int, this will keep the 126 but lose everything else    
    int truncated = a * precision; // multiplying by the precision ensures we keep that many digits

    // convert it back to a float
    // Of course, we need to ensure we're doing floating point division
    float b = static_cast<float>(truncated) / precision;

    cout << "a: " << a << "\n";
    cout << "b: " << b << "\n";

    return 0;
}

输出:

a: 1.26384                                                                                                                    
b: 1.26

请注意,此处实际上并不是1.26。但是非常接近。

这可以通过使用setprecision()来演示:

cout << "a: " << std:: setprecision(10) << a << "\n";
cout << "b: " << std:: setprecision(10) << b << "\n";

输出:

a: 1.263839006                                                                                                                
b: 1.25999999

同样,它不是完全1.26,而是非常接近,并且比以前更接近。

答案 4 :(得分:0)

使用import SwiftUI import Combine struct ServerMessage : Decodable { let status, message: String } class HttpAuth: ObservableObject { var didChange = PassthroughSubject<HttpAuth, Never>() @Published var authenticated = false { didSet{ didChange.send(self) } } func checkDetails(username: String, password: String) { guard let url = URL(string: "https://example.com") else { return } let body: [String: String] = ["username": username, "password": password ] let finalBody = try! JSONSerialization.data(withJSONObject: body) var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = finalBody request.setValue("application/json", forHTTPHeaderField: "Content-Type") URLSession.shared.dataTask(with: request) { (data, response, error) in guard let data = data else { return } let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data) print(finalData) if finalData.status == "ok" { DispatchQueue.global().async { HttpAuth.authenticated = true //ERROR: Instance member 'authenticated' cannot be used on type 'HttpAuth' print("correct credentials") } } }.resume() } } struct loginView: View { @State private var username: String = "" @State private var password: String = "" @State var server = HttpAuth() var body: some View { VStack{ TextField("Username", text: $username) .textFieldStyle(RoundedBorderTextFieldStyle()) .frame(width: 200, height: nil) .multilineTextAlignment(.center) .disableAutocorrection(true) .accessibility(identifier: "Username") .autocapitalization(.none) SecureField("Password", text: $password) .textFieldStyle(RoundedBorderTextFieldStyle()) .frame(width: 200, height: nil) .multilineTextAlignment(.center) .disableAutocorrection(true) .accessibility(identifier: "Password") Button(action: { self.server.checkDetails(username: self.username, password: self.password) //print(self.username + ", " + self.password) }) { HStack{ Spacer() Text("Login").font(.headline).foregroundColor(.white) Spacer() }.padding(.vertical, 10) .background(Color.red) .padding(.horizontal, 40) } if self.server.authenticated { Text("Correct Credentials") } //ERROR: 'String' is not convertible to 'Any' } } } struct loginView_Previews: PreviewProvider { static var previews: some View { loginView() } } 是实现这一目标的简便方法:

stringstream