解析json字符串数字失去最小精度

时间:2015-09-15 10:06:19

标签: c# json unity3d string-parsing

我正在使用C#(Unity3D兼容= .NET 2.0)Json库,我遇到了精确问题。首先,我有这个逻辑来解析数字字符串:

from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from time import sleep
client = ModbusClient('ip_address_of_modbus_IO')
if(client.connect()):
    print(client.read_discrete_inputs(200,1).bits[0])
    client.write_coil(0,True)
    sleep(100)
    client.write_coil(2,True)

问题来了,因为对于大十进制数,十进制类型不是最好的类型。我有一个输出日志来显示问题(使用.ToString()):

...
string jsonPart ="-1.7555215491128452E-19"
enter code here
long longValue = 0;
if (long.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out longValue))
{
    if (longValue > int.MaxValue || longValue < int.MinValue)
    {
        jsonPartValue = new JsonBasic(longValue);
    }
    else
    {
        jsonPartValue = new JsonBasic((int)longValue);
    }
}
else
{
    decimal decimalValue = 0;
    if (decimal.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out decimalValue))
    {
        jsonPartValue = new JsonBasic(decimalValue);
    }
}
...

但另一方面,这个十进制类型的例子是正确的:

String = "-1.7555215491128452E-19"
Float Parsed : -1.755522E-19
Double parsed : -1.75552154911285E-19
Decimal Parsed : -0.0000000000000000001755521549

我认为还有许多其他案例可以平衡到一种或另一种。 是否有任何聪明的方法来解析它失去最低精度?

1 个答案:

答案 0 :(得分:1)

您看到的差异是因为,虽然decimal可以容纳高达28或29位数的精度,而双倍的15或16位数,但其范围远低于double

A decimal has a range of (-7.9 x 10^28 to 7.9 x 10^28) / (10^(0 to 28))

A decimal存储所有数字,包括小数点后面的零,前面有零(例如0.00000001) - 即它不使用指数格式存储数字。

A double has a range of ±5.0 × 10^−324 to ±1.7 × 10^308

double可以使用指数格式存储数字,这意味着它不必将前导零存储在0.0000001之类的数字中。

这样做的结果是,对于位于小数范围边缘的数字,它实际上具有比双精度更低的精度。

例如,请考虑数字-1.7555215491128452E-19

将其转换为非指数表示法:

-0.00000000000000000017555215491128452
            1         2         3
   12345678901234567890123456789012345

你可以看到它的小数位数为35,超出了decimal的范围。

正如您所观察到的那样,当您将该数字存储在decimal后打印出来时,您会得到:

-0.0000000000000000001755521549
           1         2         
   1234567901234567890123456789

根据微软的规范,只给你29位数字。

然而,double使用指数表示法存储其数字,这意味着它不存储所有前导零,这使它能够以更高的精度存储该特定数字。

例如,double-0.00000000000000000017555215491128452存储为具有15或16位精度的指数数字。

如果从上面的数字中取15位数的精度,你会得到:

-0.000000000000000000175552154911285
                              1
                     123456789012345

如果你这样做的确是打印出来的:

double d = -1.7555215491128452E-19;
Console.WriteLine(d.ToString("F35"));