请检查发送给您的精度更高的精度。语言通常会限制打印的精度,以使其看起来更好。
var n = Number(0.005);
console.log(n);
0.005
console.log(n.toPrecision(100));
0.00500000000000000010408340855860842566471546888351440429687500000000...
,
更新
这是fixed in next release (5.0.0-preview4)。
原始答案
我测试了float
和double
,有趣的是,在此特定情况下,只有double
出现了问题,而float
似乎有效(即读取0.005)服务器)。
检查消息字节建议将0.005作为类型Float32Double
发送,尽管Number
是64位浮点,它还是4字节/ 32位IEEE 754单精度浮点数。
在控制台中运行以下代码,确认以上内容:
msgpack5().encode(Number(0.005))
// Output
Uint8Array(5) [202,59,163,215,10]
mspack5 确实提供了强制64位浮点的选项:
msgpack5({forceFloat64:true}).encode(Number(0.005))
// Output
Uint8Array(9) [203,63,116,122,225,71,174,20,123]
但是, signalr-protocol-msgpack 不使用forceFloat64
选项。
尽管这解释了float
在服务器端but there isn't really a fix for that as of now上起作用的原因。让我们等Microsoft says。
可能的解决方法
TL; DR
JS客户端向C#后端发送单个浮点数的问题导致了一个已知的浮点问题:
// value = 0.00499999988824129,crazy C# :)
var value = (double)0.005f;
要直接在方法中使用double
,可以通过自定义MessagePack.IFormatterResolver
解决此问题:
public class MyDoubleFormatterResolver : IFormatterResolver
{
public static MyDoubleFormatterResolver Instance = new MyDoubleFormatterResolver();
private MyDoubleFormatterResolver()
{ }
public IMessagePackFormatter<T> GetFormatter<T>()
{
return MyDoubleFormatter.Instance as IMessagePackFormatter<T>;
}
}
public sealed class MyDoubleFormatter : IMessagePackFormatter<double>,IMessagePackFormatter
{
public static readonly MyDoubleFormatter Instance = new MyDoubleFormatter();
private MyDoubleFormatter()
{
}
public int Serialize(
ref byte[] bytes,int offset,double value,IFormatterResolver formatterResolver)
{
return MessagePackBinary.WriteDouble(ref bytes,offset,value);
}
public double Deserialize(
byte[] bytes,IFormatterResolver formatterResolver,out int readSize)
{
double value;
if (bytes[offset] == 0xca)
{
// 4 bytes single
// cast to decimal then double will fix precision issue
value = (double)(decimal)MessagePackBinary.ReadSingle(bytes,out readSize);
return value;
}
value = MessagePackBinary.ReadDouble(bytes,out readSize);
return value;
}
}
并使用解析器:
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MyDoubleFormatterResolver.Instance,ContractlessStandardResolver.Instance,};
});
解析器并不完美,因为先转换为decimal
然后转换为double
会减慢该过程,并降低it could be dangerous。
但是
根据评论中指出的OP,如果使用具有double
返回属性的复杂类型,则无法解决问题。
进一步的调查揭示了MessagePack-CSharp中问题的原因:
// Type: MessagePack.MessagePackBinary
// Assembly: MessagePack,Version=1.9.0.0,Culture=neutral,PublicKeyToken=b4a0369545f0a1be
// MVID: B72E7BA0-FA95-4EB9-9083-858959938BCE
// Assembly location: ...\.nuget\packages\messagepack\1.9.11\lib\netstandard2.0\MessagePack.dll
namespace MessagePack.Decoders
{
internal sealed class Float32Double : IDoubleDecoder
{
internal static readonly IDoubleDecoder Instance = (IDoubleDecoder) new Float32Double();
private Float32Double()
{
}
public double Read(byte[] bytes,out int readSize)
{
readSize = 5;
// The problem is here
// Cast a float value to double like this causes precision loss
return (double) new Float32Bits(bytes,checked (offset + 1)).Value;
}
}
}
当需要将单个float
数字转换为double
时使用上述解码器:
// From MessagePackBinary class
MessagePackBinary.doubleDecoders[202] = Float32Double.Instance;
v2
MessagePack-CSharp的v2版本中存在此问题。我已经提交了an issue on github,though the issue is not going to be fixed。
本文链接:https://www.f2er.com/2566134.html