字符串编码返回错误值 33.48 变成 33.47999999999999488

问题描述

我试图在将给定对象快速转换为字符串后创建它的散列,但字符串中返回的编码值不同。

    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        // The web API will only accept tokens 1) for users,and 2) having the "TestScope" scope for this API
        static readonly string[] scoperequiredByApi = new string[] { "TestScope" };

        [HttpGet]
        public string Get()
        {
            HttpContext.VerifyUserHasAnyAcceptedScope(scoperequiredByApi);

            return "test";
        }
    }

此处在 myObjectValues 中包含一个 Decimal 值 33.48。如果我尝试将此 mydata 编码为字符串,则返回的值为 33.47999999999999488。我试图将十进制值四舍五入到 2 位,但最后的字符串不断发布这个数字。我试图将它保存在字符串中,然后返回到十进制,但编码字符串中返回的值仍然是 33.479999999ish。

我不能使用字符串来计算和比较哈希值,因为从服务器返回的哈希值是 33.48,这永远不会等于我用这个长值得到的结果。

解决方法

使用基础 Decimal 值创建的

Double 值总是会产生这些问题。

使用基础 Decimal 值创建的

String 值不会产生这些问题。

你可以尝试做的是 -

  1. 有一个私有的 String 值作为后备存储,用于安全地编码和解码这个十进制值。
  2. 公开另一个使用此基础 Decimal 值的计算出的 String 值。
import Foundation

class Test: Codable {
    // Not exposed : Only for encoding & decoding
    private var decimalString: String = "33.48"
    
    // Work with this in your app
    var decimal: Decimal { 
        get { 
            Decimal(string: decimalString) ?? .zero
        }
        set { 
            decimal = newValue 
            decimalString = "\(newValue)"
        }
    }
}

do {
    let encoded = try JSONEncoder().encode(Test())
    print(String(data: encoded,encoding: .utf8))
    // Optional("{\"decimalString\":\"33.48\"}")
    
    let decoded = try JSONDecoder().decode(Test.self,from: encoded)
    
    print(decoded.decimal) // 33.48
    print(decoded.decimal.nextUp) // 33.49
    print(decoded.decimal.nextDown) // 33.47
} catch {
    print(error)
}
,

我试图在将给定对象快速转换为字符串后创建它的散列,但字符串中返回的编码值不同。

不要这样做。只是不要。这是不明智的。

我将通过类比来解释它:想象一下,如果你用六位十进制数字的精度来表示数字。你必须使用一些精度,对吗?

现在,1/3 将表示为 0.333333。但是 2/3 将由 0.666667 表示。所以现在,如果你将 1/3 乘以 2,你将不会得到 2/3。如果你把 1/3 加到 1/3 到 1/3,你就不会得到 1。

所以 1 的哈希值会因你如何得到 1 而不同!如果你把 1/3 加到 1/3 到 1/3,你会得到一个不同于你加 2/3 到 1/3 的哈希值。

这根本不是哈希的正确数据类型。不要为此目的使用双打。舍入会起作用,直到它不起作用。

而您使用的是 33 + 48/100 -- 这个值不能以 2 为底数准确表示,就像 1/3 不能以 10 为底数准确表示一样。