在不改变目标类型的情况下以最高精度序列化浮点数

2024-04-16

我需要反序列化原始二进制数据 (BinaryFormatter),然后序列化为 JSON(用于编辑),然后再次将其序列化回二进制。 显然,我输在了浮动上。原始浮点值0xF9FF4FC1(大端,大致-12.9999933)四舍五入为0xF6FF4FC1 (-12.99999)当我序列化时原始二进制文件(正确数据和中间数据在内存中是1:1)JSON。我知道这并不是一个很大的损失,而且我知道浮动是有问题的,但由于以后可能出现不兼容问题,我想保持尽可能接近的精度。

有人用 JSON 解决过这个问题吗?如何强制它以最大精度写入浮点数?我已经尝试过将浮点数处理为十进制或双精度的内置选项,但不幸的是,输出没有区别,而且我无法更改目标值,因为当我进行二进制序列化时,它们仍然需要写为浮点数,因此会进行舍入无论在隐式转换期间。

我想要往返的包含浮动的特定类型是Vector2 from https://github.com/FNA-XNA/FNA/blob/master/src/Vector2.cs https://github.com/FNA-XNA/FNA/blob/master/src/Vector2.cs.

tl:dr 有一个浮点数,希望 JsonNET 将其尽可能精确地序列化为最终的 json 字符串。

附:我在这里阅读了大量的问题和其他地方的博客文章,但没有发现任何人试图解决同样的问题,大多数搜索命中都与浮动阅读问题有关(我稍后也需要解决)。

UPDATE:正如下面的 @dbc 所指出的 - Jsont.NET 尊重“TypeConverter”属性,因此我必须制作自己的转换器来覆盖它。


Json.NET将序列化float使用往返精度格式的值"R" (source https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/JsonConvert.cs#L261)。但是,您使用的类型,https://github.com/FNA-XNA/FNA/blob/master/src/Vector2.cs https://github.com/FNA-XNA/FNA/blob/master/src/Vector2.cs, has a TypeConverter应用:

    [Serializable]
    [TypeConverter(typeof(Vector2Converter))]
    [DebuggerDisplay("{DebugDisplayString,nq}")]
    public struct Vector2 : IEquatable<Vector2>
    {
        //...

正如中所解释的牛顿软件文档 http://www.newtonsoft.com/json/help/html/SerializationGuide.htm,此类类型将使用转换器序列化为字符串:

原始类型

.Net: TypeConverter(可转换为字符串)
JSON:字符串

并且,检查代码https://github.com/FNA-XNA/FNA/blob/master/src/Design/Vector2Converter.cs https://github.com/FNA-XNA/FNA/blob/master/src/Design/Vector2Converter.cs,看来这个转换器是not转换为字符串时使用往返精度格式,位于60号线左右 https://github.com/FNA-XNA/FNA/blob/master/src/Design/Vector2Converter.cs#L60:

    return string.Join(
        culture.TextInfo.ListSeparator,
        new string[]
        {
            vec.X.ToString(culture),
            vec.Y.ToString(culture)
        }
    );

因此内置的TypeConverter它本身就是你失去精度的地方。

为了避免这个问题,您可以

  1. 创建一个custom JsonConverter http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm for Vector2例如以下内容:

    public class Vector2Converter : JsonConverter
    {
        class Vector2DTO
        {
            public float X;
            public float Y;
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Vector2) || objectType == typeof(Vector2?);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // A JSON object is an unordered set of name/value pairs so the converter should handle
            // the X and Y properties in any order.
            var dto = serializer.Deserialize<Vector2DTO>(reader);
            if (dto == null)
                return null;
            return new Vector2(dto.X, dto.Y);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var vec = (Vector2)value;
            serializer.Serialize(writer, new Vector2DTO { X = vec.X, Y = vec.Y });
        }
    }
    

    如果您将转换器添加到JsonSerializerSettings.Converters https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonSerializerSettings_Converters.htm它将取代TypeConverter.

    工作样本小提琴here https://dotnetfiddle.net/kDHzkd.

    转换器将序列化Vector2作为一个对象X and Y属性,但如果您愿意,也可以将其序列化为具有两个值的数组。我不建议将序列化为原始类型string since Vector2不对应于 JSON 原语。

  2. Use a 自定义合约解析器 https://www.newtonsoft.com/json/help/html/contractresolver.htm#CustomIContractResolverExamples这不会为类型创建原始契约TypeConverter应用,例如答案中所示的Newtonsoft.JSON 无法使用 TypeConverter 属性转换模型 https://stackoverflow.com/q/31325866/3744182.

Notes:

  • 往返形式"R"显然不保留之间的差异+0.0 and -0.0,所以 Json.NET 也没有,请参阅https://dotnetfiddle.net/aereJ2 https://dotnetfiddle.net/aereJ2 or https://dotnetfiddle.net/DwoGyX https://dotnetfiddle.net/DwoGyX进行演示。这微软文档 https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#the-round-trip-r-format-specifier没有提及使用此格式时是否应保留零符号。

    因此,这是一种往返 a 的情况float可能会导致二进制更改。

    (谢谢@chux https://stackoverflow.com/users/2410359/chux提出这个问题comments https://stackoverflow.com/questions/51703481/serializing-float-with-maximum-precision-without-changing-target-type/51705781#comment90378398_51705781.)

  • 顺便说一句,Json.NET 也使用"R"写作时double(如图所示来源JsonConvert.ToString(double value, ...) https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/JsonConvert.cs#L296):

    internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
    {
        return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
    }
    

    For double only这种格式被记录为可能会失去精度。从往返(“R”)格式说明符 https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#the-round-trip-r-format-specifier:

    在某些情况下,如果使用“R”标准数字格式字符串进行格式化的 Double 值无法成功往返/platform:x64 or /platform:anycpu交换机并在 64 位系统上运行。

    因此往返adouble通过 Json.NET 可能会导致小的二进制差异。然而,这并不严格适用于这里的问题,该问题具体是关于float.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在不改变目标类型的情况下以最高精度序列化浮点数 的相关文章

  • 调试Windows服务

    Scenario 我有一个用 C 编写的 Windows 服务 我已经阅读了所有关于如何调试它的谷歌线程 但我仍然无法让它工作 我已经运行 PathTo NetFramework InstallUtil exe C MyService ex
  • 在剑道网格中显示动态图像

    我想在剑道网格中填充动态图像 我正在获取 json 数据 我有以下代码 var grid timeSegmentGrid kendoGrid var icon dataSource transport read function optio
  • Xamarin 中的 Task.ConfigureAwait(false) - 安全使用/建议使用?

    经验法则是 如果它不是与 UI 相关的方法 请使用Task ConfigureAwait false 如果我有一个接受接口的 PCL 核心库怎么办IUIAccess 核心库中的视图模型有一个方法 public Task ViewModelL
  • 如何防止通过“new”运算符分配类? (我想确保我的 RAII 类始终分配在堆栈上。)

    我想确保我的 RAII 类始终分配在堆栈上 如何防止通过 new 运算符分配类 您需要做的就是将类的 new 运算符声明为私有 class X private Prevent heap allocation void operator ne
  • 如何在 javascript 中使用 .net 资源文件

    无论如何 我可以在 javascript 中访问我的资源文件 resx 吗 如果没有 那么是否有任何解决方法可以用不同语言的 javascript 显示消息 如果您的 javascript 在页面中 您可以使用 var globalReso
  • 公开 ASP.NET 用户控件中的复杂属性

    我想从自定义 ASP NET 用户控件公开一个复杂的属性 可以通过aspx页面中的控制标签来设置 像这样的事情 public class TestData public int X public int Y public partial c
  • 使用 Xlib 捕获鼠标

    我想编写一个简单的 Xlib 程序来改变鼠标行为 举个例子 反转垂直移动 我在捕获事件时遇到问题 我想要代码 捕获控制器位置的变化 我向上移动鼠标 MotionEvent 计算新的光标位置 new x difference x 设置新的光标
  • 无法使用 process.ErrorDataReceived c# 获取进程错误输出

    我已经建立了Form我使用了一段时间的应用程序 现在我想捕捉StandardError我的流程及其standartOutput 我查看了答案SO and MSDN https msdn microsoft com en us library
  • MDI应用程序中父窗体的问题

    我使用按钮作为容器中的控件 父窗体 当子窗体出现时 父窗体中的控件 按钮 图片 标签 出现在子窗体上并将其覆盖 我看不到子窗体 有谁知道如何防止这种情况 我不想将这些控件设置为 Control Visible false 因为当我最小化子表
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • FormsAuthentication.SetAuthCookie() 是否需要重定向?

    检查用户的凭据并确认其良好后 我正在使用FormsAuthentication SetAuthCookie Username false 对用户进行身份验证 然后在母版页中我使用Page User Identity IsAuthentica
  • 使用 ASP.NET Core Identity 将令牌保存在 Cookie 中

    我想在我的 身份 生成的 cookie 中保存一些内容 我目前正在使用文档中的默认身份设置 启动 cs services Configure
  • IBM Rhapsody 中状态图终止连接器的理解

    在IBM Rhapsody中 如果我使用new创建了一个类的实例 那么我们是否必须通过调用delete来处理内存的释放 或者Termination Connector将在其状态图中通过内存释放来处理其销毁 如果您使用 C 和 OXF 对象执
  • 将引用托管代码中分配的内存的指针传递给非托管代码

    我在 C 中分配了一个大的 char 缓冲区 并且希望将指向此数据的指针传递给 DLL 中的未管理的 c 函数 现在我认为要使其工作 必须修复字符缓冲区 以便 GC 在函数工作时无法移动它 如果是这样 我会声明缓冲区已固定并调用 UNSAF
  • LINQ 表达式树 Any() 位于Where() 内

    我正在尝试生成以下 LINQ 查询 Query the database for all AdAccountAlerts that haven t had notifications sent out Then get the entity
  • MDI 窗体中的子窗口对接

    我有一个 MDI 表单和其中的一些子表单 我将子窗体停靠到 MDI 窗口的不同区域 但是当任何子窗体失去焦点时 其他停靠的窗体将重新排列 由于混乱 我准备了一组图像来展示该行为 Image1 单击任何窗口之前 Image2 点击窗口2后 问
  • 将 tiff 像素长宽比更改为正方形

    我正在尝试对多页 tiff 文件执行条形码识别 但是 tiff 文件是从传真服务器 我无法控制 发送给我的 该服务器以非方形像素长宽比保存 tiff 这导致图像由于纵横比而被严重挤压 我需要将 tiff 转换为方形像素长宽比 但不知道如何在
  • Security.h 中结构的 macOS 文档

    我正在尝试使用Security h通过 Java 和 JNA 的 macOS 框架 这意味着我需要将某些结构重建为 Java 类 问题是 当我查看文档中的结构时 this one https developer apple com refe
  • 生成唯一随机数的智能方法

    我想生成 00000001 到 99999999 范围内的唯一随机数序列 所以第一个可能是 00001010 第二个可能是 40002928 等等 最简单的方法是生成一个随机数并将其存储在数据库中 下次再执行一次并检查数据库中该数字是否已存
  • 为什么 typeof 函数在 C 中不起作用

    我使用GCC编译器 版本9 2 0 我想在 C 中使用 typeof 函数 但它会引发错误 错误 typeof 之前的预期表达式 如果您需要更多信息 请询问我 int a 5 double b the expected result is

随机推荐

  • 使用AppService的连接持续时间有限制吗?

    我有一个 UWP 应用程序托管应用服务 https learn microsoft com en us windows uwp launch resume how to create and consume an app service在同
  • Pyspark 错误:Java 网关进程在发送其端口号之前退出

    我正在使用 Pyspark 在 Jupyter Notebook 中运行一些命令 但它抛出错误 我尝试了此链接中提供的解决方案 Pyspark 异常 Java 网关进程在向驱动程序发送其端口号之前退出 https stackoverflow
  • /usr/bin/ld: 找不到 -llibeststring.a

    我在我的程序中使用 Festival TTS C API 我已经从以下位置下载了所有文件http www cstr ed ac uk downloads festival 2 0 95 http www cstr ed ac uk down
  • Python urllib2.urlopen() 很慢,需要更好的方法来读取多个 url

    正如标题所示 我正在开发一个用 python 编写的网站 它多次调用 urllib2 模块来读取网站 然后我用 BeautifulSoup 解析它们 由于我必须阅读 5 10 个网站 因此页面需要一段时间才能加载 我只是想知道是否有办法一次
  • 在 iOS 5 中播放视频

    我正在尝试遵循本教程link http www techotopia com index php Video Playback from within an iOS 5 iPhone Application 但我有问题 有人可以看一下并让我
  • oracle pl/sql中的XML解析

    我正在尝试在 PL SQL 中解析此 XML
  • 在 WHERE 中使用 ROW_NUMBER() 别名[重复]

    这个问题在这里已经有答案了 在 Postgresql 9 1 中 我尝试使用 ROW NUMBER 别名字段过滤 WHERE 子句中的结果集 这个查询工作正常 SELECT inv client pk inv invoice pk inv
  • 监听来自UIWebView的所有请求

    我可以使用以下方法拦截来自 UIWebView 的初始加载请求 BOOL webView UIWebView webView shouldStartLoadWithRequest NSURLRequest request navigatio
  • 在 Javascript 中声明函数最有效的方法是什么?

    我一直了解到 要在 javascript 中声明函数 您应该执行以下操作 function myfunction fruit alert I like fruit 或类似的东西 var myfunction function fruit a
  • 如何获取子 ng-repeat 内父作用域数组/ng-repeat 的索引

    我正在建一张桌子 我有两张桌子ng repeat为了我的桌子 我的问题是 这是否有可能是ng repeat可以得到父级ng repeat的索引 例如 tbody tr td company the company index and pro
  • 为什么 Google 的 OpenID 实现的 ID 会发生变化?

    我正在尝试为 Web 应用程序实现 OpenId 登录 每当新用户通过 OpenId 登录时 我都会在系统上创建一个新用户 并在数据中存储他们的 openid URL 以便下次他们使用该用户登录时 我正在使用 Gmail OpenID 对此
  • 如何为armv6、armv7和i386编译静态库(fat)

    我知道这个问题已经被提出过好几次了 但我的目标与我在网上搜索到的内容略有不同 具体来说 我已经能够为 iPhone 构建静态库 但我能够构建的最终 fat 文件仅包含arm和i386架构 并且我不确定arm指的是 v6还是v7 我无法专门针
  • C++ 中谓词是什么? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 您能举一些例子或主题链接吗 谓词是一
  • Jquery中的onclick函数不起作用

    在product showcase js 文件的帮助下 我将内容加载到 HTML 中 然后使用以下类单击产品链接即内在我正在尝试组织一个单击事件如product description js所示 数据是从 json 文件中获取的 我能够将数
  • 将照片上传到 MVC 4 应用程序

    我正在尝试创建一个控制器来在我的 MVC4 应用程序中上传照片 但我不断收到此错误 输入不是有效的 Base 64 字符串 因为它包含非 Base 64 字符 两个以上的填充字符或填充字符中包含非空白字符 照片控制器 cs public c
  • 使用 php 客户端库 v3 将视频上传到 youtube

    我正在尝试使用客户端库 v3 将视频上传到 youtube v3 库是实验性的 没有太多文档 提供的示例不包括 youtube 我已经使用 oauth 2 0 正确验证了用户身份 当我拥有访问令牌时 我正在尝试使用此代码 if client
  • 如何根据给定名称查找一个类的所有子类?

    我需要一种获取从 Python 基类继承的所有类的工作方法 新式类 即从object 这是 Python 3 中的默认设置 subclasses 返回子类的方法 class Foo object pass class Bar Foo pas
  • Xcode 4模板,创建空组

    我正在尝试创建一个 xcode 4 模板 除了我无法创建空组之外 一切工作正常 我想要这个项目结构 项目名 楷模 控制器 景观 服务
  • 检查字典的任何值是否与条件匹配[重复]

    这个问题在这里已经有答案了 python程序员如何检查字典的任何值是否匹配条件 大于0就我而言 我正在寻找对性能影响最小的最 Pythonic 方式 我的字典 pairs word1 0 word2 0 word3 2000 word4 6
  • 在不改变目标类型的情况下以最高精度序列化浮点数

    我需要反序列化原始二进制数据 BinaryFormatter 然后序列化为 JSON 用于编辑 然后再次将其序列化回二进制 显然 我输在了浮动上 原始浮点值0xF9FF4FC1 大端 大致 12 9999933 四舍五入为0xF6FF4FC