Delphi中通过writeln / readln实现的实数精度

时间:2020-03-06 14:53:20  来源:igfitidea点击:

我的客户应用程序使用writeln和readln通过文本文件导出和导入了许多real类型的变量。我试图增加所写字段的宽度,因此代码如下所示:

writeln(file, exportRealvalue:30); //using excess width of field
....
readln(file, importRealvalue);

当我导出然后再次导入和导出并比较文件时,我得到的最后两位数有所不同,例如(可能在此处的实际位数上有误,但我们会得到它):

-1.23456789012E-0002
-1.23456789034E-0002

这实际上在应用程序中有所作为,因此客户想知道我能对此做些什么。现在,我不确定是不是只有写/读才能做到这一点,但我认为在再次进入嘿堆栈之前,我会在这里提出一个快速问题。我是否需要对此进行二进制处理?

这不是一个处理货币或者其他东西的应用程序,我只是在文件中读写值。我知道有时候浮点数有点奇怪,我认为其中一个例程(writeln / readln)可能正在进行一些有趣的事情。

解决方案

使用浮点类型时,应注意指定类型的精度限制。例如,一个4字节的IEEE-754类型只有大约7.5个有效数字的精度。八字节的IEEE-754类型的有效位数大约是原来的两倍。显然,delphi实数类型的精度约为11个有效数字。这样的结果是,我们指定的格式的任何额外数字都可能是噪音,可能导致以10为基数的格式化值和以2为基数的浮点值之间的转换。

我们可以尝试切换到扩展模式以获得更高的精度。如前所述,浮点数仅具有这么多的有效位数,因此仍然有可能显示更多的数字然后进行精确存储,这可能会导致我们指定的行为。

从Delphi帮助:

基本Win32实型

| Significant | Size in 
Type     | Range                            | digits      | bytes
---------+----------------------------------+-------------+----------
Real     | -5.0 x 10^–324 .. 1.7 x 10^308   | 15–16       |   8  
Real48   | -2.9 x 10^–39 .. 1.7 x 10^38     | 11-12       |   6   
Single   | -1.5 x 10^–45 .. 3.4 x 10^38     |  7-8        |   4   
Double   | -5.0 x 10^–324 .. 1.7 x 10^308   | 15-16       |   8   
Extended | -3.6 x 10^–4951 .. 1.1 x 10^4932 | 10-20       |  10   
Comp     | -2^63+1 .. 2^63–1                | 10-20       |   8   
Currency | -922337203685477.5808..          |             | 
                    922337203685477.5807    | 10-20       |   8
Note: The six-byte Real48 type was called Real in earlier versions of Object Pascal. If you are recompiling code that uses the older, six-byte Real type in Delphi, you may want to change it to Real48. You can also use the {$REALCOMPATIBILITY ON} compiler directive to turn Real back into the six-byte type. The following remarks apply to fundamental real types. 
  
  
  Real48 is maintained for backward compatibility. Since its storage format is not native to the Intel processor architecture, it results in slower performance than other floating-point types. 
  Extended offers greater precision than other real types but is less portable. Be careful using Extended if you are creating data files to share across platforms.

请注意,范围大于有效数字。因此,我们可以拥有更大的数字,然后可以准确地进行存储。我建议四舍五入到有效数字以防止这种情况发生。

首先,我将尝试查看是否可以通过将Str与其他参数一起使用或者提高应用程序类型的精度来获得任何帮助。 (我们尝试过使用扩展吗?)

作为最后的选择,(警告!解决方法!!)我将尝试将客户的字符串表示形式以及二进制表示形式保存在排序列表中。在写回浮点值之前,我将查看表中是否已经有一个匹配值,该值的字符串表示形式已经为人所知,可以替代使用。为了快速进行此查找,我们可以将其按数值排序,并使用二进制搜索来找到最佳匹配项。

如果要使用WriteLn指定实数的精度,请使用以下命令:

WriteLn(RealVar:12:3);

输出的Realvar值至少有12个位置,精度为3.

根据我们需要执行多少处理,另一种方法是将数字保持为BCD格式以保持原始精度。

如果不知道ExportRealValue和ImportRealValue是什么类型,就很难回答。正如其他人提到的那样,实类型都具有不同的精度。

值得一提的是,与某些想法相反,扩展并不总是具有更高的精度。扩展了10-20个有效数字,其中两倍是15-16. 当我们在第十个无花果周围遇到问题时,也许我们已经在使用扩展。

为了更好地控制读写,我们可以自己将数字与字符串进行相互转换,然后将其写入文件流。至少以这种方式,我们不必担心readln和writeln背后没有任何好处。