当前位置:  开发笔记 > 编程语言 > 正文

F#浮点范围是实验性的,可能已弃用

如何解决《F#浮点范围是实验性的,可能已弃用》经验,为你挑选了2个好方法。

我正在尝试使用给定的增量在两个值之间进行插值.

[ 1.0 .. 0.5 .. 20.0 ]

编译器告诉我这已被弃用,并建议使用ints然后转换为float.但是如果我有一个小数增量,这似乎有点啰嗦 - 我是否必须将我的开始值和结束值除以我的增量,然后再将多次除以?(yeuch!).

我曾经看过一些关于使用序列理解来做这件事的事情,但我不记得是怎么回事.

请帮忙.



1> bytebuster..:

TL; DR:F#PowerPack的BigRational类型是要走的路.


浮点循环有什么问题

正如许多人所指出的,float值不适合循环:

它们确实有Round Off Error,就像1/3十进制一样,我们不可避免地会丢失从某个指数开始的所有数字;

他们确实经历了灾难性的取消(当减去两个几乎相等的数字时,结果四舍五入为零);

它们总是具有非零的机器epsilon,因此每次数学运算都会增加错误(除非我们多次添加不同的数字以便错误相互抵消 - 但这不是循环的情况);

它们在整个范围内具有不同的准确度:范围中的唯一值[0.0000001 .. 0.0000002]的数量等于其中的唯一值的数量[1000000 .. 2000000];

能够立即解决上述问题的是切换回整数逻辑.

使用F#PowerPack,您可以使用以下BigRational类型:

open Microsoft.FSharp.Math
// [1 .. 1/3 .. 20]
[1N .. 1N/3N .. 20N]
|> List.map float
|> List.iter (printf "%f; ")

注意,我冒昧地设置了步骤,1/3因为0.5从你的问题实际上有一个精确的二进制表示0.1 b并表示为+1.00000000000000000000000*2 -1 ; 因此它不会产生任何累积求和误差.

输出:

1.000000; 1.333333; 1.666667; 2.000000; 2.333333; 2.666667; 3.000000; (已跳过) 18.000000; 18.333333; 18.666667; 19.000000; 19.333333; 19.666667; 20.000000;

// [0.2 .. 0.1 .. 3]
[1N/5N .. 1N/10N .. 3N]
|> List.map float
|> List.iter (printf "%f; ")

输出:

0.200000; 0.300000; 0.400000; 0.500000; (已跳过) 2.800000; 2.900000; 3.000000;

结论

BigRational使用整数计算,它不比浮点 ;

每个值只发生一次舍入(转换为a float,但不在循环内);

BigRational 表现为机器epsilon为零;

有一个明显的局限性:你不能使用非理性数字pi,sqrt(2)因为它们没有精确的表示作为分数.它似乎并不成为一个非常大的问题,因为通常情况下,我们没有遍历两个有理数和无理数,例如[1 .. pi/2 .. 42].如果我们这样做(比如几何计算),通常会有一种减少无理部分的方法,例如从弧度切换到度数.


进一步阅读:

每个计算机科学家应该知道的浮点运算

PowerPack中的数字类型



2> Stephen Swen..:

有趣的是,浮动范围似乎不再被弃用.我记得最近看到一个问题(抱歉,无法追踪它),谈论浮动范围所表现出来的固有问题,例如

> let xl = [0.2 .. 0.1 .. 3.0];;

val xl : float list =
  [0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
   1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9]

我只是想指出,你可以在decimal类型上使用范围,而不是这些舍入问题,例如

> [0.2m .. 0.1m .. 3.0m];;
val it : decimal list =
  [0.2M; 0.3M; 0.4M; 0.5M; 0.6M; 0.7M; 0.8M; 0.9M; 1.0M; 1.1M; 1.2M; 1.3M;
   1.4M; 1.5M; 1.6M; 1.7M; 1.8M; 1.9M; 2.0M; 2.1M; 2.2M; 2.3M; 2.4M; 2.5M;
   2.6M; 2.7M; 2.8M; 2.9M; 3.0M]

如果你真的确实需要花车,那么你可以做类似的事情

> {0.2m .. 0.1m .. 3.0m} |> Seq.map float |> Seq.toList;;
val it : float list =
  [0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
   1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9; 3.0]

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有