হালনাগাদ
এটি পরবর্তী প্রকাশে (5.0.0-প্রাকদর্শন 4) স্থির করা হয়েছে ।
আসল উত্তর
আমি পরীক্ষিত float
এবং double
, এবং মজার ব্যাপার এই বিশেষ ক্ষেত্রে, শুধুমাত্র double
, সমস্যা যেহেতু float
কাজ করা (অর্থাত 0.005 সার্ভারে পড়া হয়) বলে মনে হয়।
বার্তা বাইটগুলি পরিদর্শন করে পরামর্শ দেওয়া হয়েছে যে 0.005 টাইপ হিসাবে প্রেরণ করা হয় Float32Double
যা 4-বাইট / 32-বিট আইইইই 754 একক নির্ভুলতা ফ্লোটিং পয়েন্ট নম্বর সত্ত্বেও Number
64 বিট ভাসমান পয়েন্ট।
কনসোলে নিম্নলিখিত কোডটি চালিত করুন উপরোক্ত নিশ্চিত করেছেন:
msgpack5().encode(Number(0.005))
// Output
Uint8Array(5) [202, 59, 163, 215, 10]
mspack5 bit৪ বিট ভাসমান পয়েন্টকে বাধ্য করার জন্য একটি বিকল্প সরবরাহ করে:
msgpack5({forceFloat64:true}).encode(Number(0.005))
// Output
Uint8Array(9) [203, 63, 116, 122, 225, 71, 174, 20, 123]
তবে forceFloat64
বিকল্পটি সিগন্যাল-প্রোটোকল-পিক্সপ্যাক ব্যবহার করে না ।
যদিও যে ব্যাখ্যা দিয়েছে কেন float
সার্ভার প্রান্তের কাজ করে, কিন্তু সত্যিই যে এখন হিসাবে জন্য একটি ফিক্স নয় । মাইক্রোসফ্ট কি বলে অপেক্ষা করি ।
সম্ভাব্য কর্মক্ষেত্র
- হ্যাক ?? প্যাক 5 বিকল্প? আপনার নিজের ফাইলপ্যাকটি কাঁটাচামচ করে সংকলন করুন ডিফল্টর সাথে
forceFloat64
সত্য ?? আমি জানি না।
float
সার্ভারের দিকে স্যুইচ করুন
string
উভয় পক্ষের ব্যবহার করুন
decimal
সার্ভারের দিকে স্যুইচ করুন এবং কাস্টম লিখুন IFormatterProvider
। decimal
আদিম ধরণের নয়, এবং IFormatterProvider<decimal>
জটিল ধরণের বৈশিষ্ট্যের জন্য ডাকা হয়
double
সম্পত্তি মান পুনরুদ্ধার এবং double
-> float
-> decimal
-> double
কৌশল করতে পদ্ধতি সরবরাহ করুন method
- অন্যান্য অবাস্তব সমাধানগুলি যা আপনি ভাবতে পারেন
টি এল; ডিআর
জেএস ক্লায়েন্টের সাথে সি # ব্যাকএন্ডে একক ফ্লোটিং পয়েন্ট নম্বর প্রেরণ করার সমস্যাটি একটি পরিচিত ভাসমান পয়েন্ট সমস্যা সৃষ্টি করে:
// 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,
int offset,
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, offset, out readSize);
return value;
}
value = MessagePackBinary.ReadDouble(bytes, offset, out readSize);
return value;
}
}
এবং সমাধান সমাধান করুন:
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MyDoubleFormatterResolver.Instance,
ContractlessStandardResolver.Instance,
};
});
রেজোলভারটি নিখুঁত নয়, কারণ প্রক্রিয়াটি ধীর করে decimal
দেওয়ার জন্য কাস্টিং হ'ল এটি বিপজ্জনক হতে পারে ।double
যাহোক
মন্তব্যে ওপি নির্দেশিত অনুসারে, জটিল প্রকারের ফেরত সম্পত্তি থাকার কারণে এটি সমস্যার সমাধান করতে পারে নাdouble
।
আরও তদন্তে মেসেজপ্যাক-সিএসের্পে সমস্যার কারণ প্রকাশিত হয়েছে:
// 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, int offset, 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
এই সমস্যাটি মেসেজপ্যাক-সিএসের্পের v2 সংস্করণে বিদ্যমান। আমি গিথুবে একটি ইস্যু করেছি , যদিও সমস্যাটি স্থির হতে যাচ্ছে না ।