加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

algorithm – 将扩展(80位)转换为字符串

发布时间:2020-12-15 04:05:00 所属栏目:大数据 来源:网络整理
导读:如何将扩展精度浮点值转换为字符串? 背景 Intel CPU支持三种浮点格式: 32位单精度 64位双精度 80位 Extended precision Delphi本身支持Extended精度浮点格式. 扩展精度分为: 1个符号位 15个指数位 1整数部分位(即数字以0或1开头) 63尾数位 您可以将Extend
如何将扩展精度浮点值转换为字符串?

背景

Intel CPU支持三种浮点格式:

> 32位单精度
> 64位双精度
> 80位Extended precision

Delphi本身支持Extended精度浮点格式.

扩展精度分为:

> 1个符号位
> 15个指数位
> 1整数部分位(即数字以0或1开头)
> 63尾数位

您可以将Extended的尾数大小与其他float类型的尾数进行比较:

| Type     | Sign  | Exponent | Integer | Mantissa | 
|----------|-------|----------|---------|----------|
| Single   | 1 bit |  8 bits  |  n/a    | 23 bits  |
| Double   | 1 bit | 11 bits  |  n/a    | 52 bits  |
| Extended | 1 bit | 15 bits  | 1 bit   | 63 bits  |

扩展能够实现单倍和双倍的更高精度.

例如,取实数.49999999999999999,它以二进制表示:

Single:   0.1000000000000000000000000
Double:   0.10000000000000000000000000000000000000000000000000000
Extended: 0.02222222222222222222222222222222222222222222222222222222010001111

你看,当Single和Double被强制舍入到0.1二进制(0.5十进制)时,扩展仍然有一定的精度.

但是如何将二进制分数转换为字符串?

如果我尝试将扩展值0.49999999999999998转换为字符串:

FloatToStr(v);

函数返回0.5,当我在Extended中看到它并且看到它不是0.5时:

0x3FFDFFFFFFFFFFFFFD1E

其他扩展值也是如此; Delphi中的所有函数(我都能找到)都返回0.5:

Value                   Hex representation      FloatToSTr
0.499999999999999980    0x3FFDFFFFFFFFFFFFFD1E  '0.5'
0.499999999999999981    0x3FFDFFFFFFFFFFFFFD43  '0.5'
0.499999999999999982    0x3FFDFFFFFFFFFFFFFD68  '0.5'
0.499999999999999983    0x3FFDFFFFFFFFFFFFFD8D  '0.5'
0.499999999999999984    0x3FFDFFFFFFFFFFFFFDB2  '0.5'
0.499999999999999985    0x3FFDFFFFFFFFFFFFFDD7  '0.5'
0.499999999999999986    0x3FFDFFFFFFFFFFFFFDFB  '0.5'
0.499999999999999987    0x3FFDFFFFFFFFFFFFFE20  '0.5'
0.499999999999999988    0x3FFDFFFFFFFFFFFFFE45  '0.5'
0.499999999999999989    0x3FFDFFFFFFFFFFFFFE6A  '0.5'
0.499999999999999990    0x3FFDFFFFFFFFFFFFFE8F  '0.5'
...                     ...
0.49999999999999999995  0x3FFDFFFFFFFFFFFFFFFF  '0.5'

什么功能?

FloatToStr和FloatToStrF都是FloatToText左右的包装纸.

FloatToText最终使用FloatToDecimal从扩展中提取包含浮动部分的记录:

TFloatRec = packed record
   Exponent: Smallint;
   Negative: Boolean;
   Digits: array[0..20] of Byte;
end;

就我而言:

var
   v: Extended;
   fr: TFloatRec;
begin
   v := 0.499999999999999980;

   FloatToDecimal({var}fr,v,fvExtended,18,9999);
end;

解码后的浮点数返回:

>指数:0(SmallInt)
>否定:假(布尔)
>数字:[53,1](数组[0 .. 20] Byte)

数字是ascii字符数组:

>指数:0
>否定:错误
>数字:’5′

FloatToDecimal限制为18位数

扩展精度浮点数的63位尾数的精度可以降至:

1 / (2^63)  
= 1.08420217248550443400745280086994171142578125 × 10^-19   
= 0.000000000000000000108420217248550443400745280086994171142578125
    _________________/ 
            |
        19 digits

问题是:

>扩展可以为您提供有意义的值,最高可达第19位
> FloatToDecimal,最多返回20位数,仅接受并生成18位数的最大请求,用于扩展值(货币为19位)

对于文档:

For values of type Extended,the Precision parameter specifies the requested number of significant digits in the result–the allowed range is 1..18.
The Decimals parameter specifies the requested maximum number of digits to the left of the decimal point in the result.
Precision and Decimals together control how the result is rounded. To produce a result that always has a given number of significant digits regardless of the magnitude of the number,specify 9999 for the Decimals parameter.
The result of the conversion is stored in the specified TFloatRec record as follows:

Digits – Contains up to 18 (for type Extended) or 19 (for type Currency) significant digits followed by a null terminator. The implied decimal point (if any) is not stored in Digits.

所以我遇到了内置浮点格式化函数的基本限制

如何格式化80位IEEE扩展精度浮点数?

如果德尔福不能自己做,问题就变成:我该怎么做?

我知道扩展是10个字节(SizeOf(扩展)= 10).现在的问题是深入研究将IEEE浮点数转换为字符串的黑暗艺术.

有些部分很简单:

function ExtendedToDecimal(v: Extended): TFloatRec;
var
    n: UInt64;
const
    BIAS = 16383;
begin
    Result := Default(TFloatRec);

    Result.Negative := v.Sign;
    Result.Exponent := v.Exponent;
    n := v.Mantissa;
//  Result.Digits :=
end;

但困难的部分留下作为答案的练习.

奖金截图

解决方法

How can i convert an Extended precision floating point value to a string?

由于Delphi RTL没有针对Extended(和Double)的正确和完整的FloatToStr()函数的任何实现,因此需要使用外部库,找到here并且最初是在EDN,Codecentral.

该库由John Herbster创建,John Herbster是Delphi RTL库的长期撰稿人,特别是关于浮点处理. GitHub源代码已更新为使用UniCode字符串处理和TFormatSettings结构进行格式化.该库包含一个ExactFloatToStr()函数,用于处理Extended,Double和Single类型的浮点数.

Program TestExactFloatToStr; 

{$APPTYPE CONSOLE}

Uses
  SysUtils,ExactFloatToStr_JH0;

begin
  WriteLn(ExactFloatToStr(Extended(0.49999999999999999)));
  WriteLn(ExactFloatToStr(Double(0.49999999999999999)));
  WriteLn(ExactFloatToStr(Single(0.49999999999999999)));
  ReadLn;
end.

输出:

06001

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读