F# 浮点范围是实验性的,可能会被弃用 [英] F# Floating point ranges are experimental and may be deprecated

查看:26
本文介绍了F# 浮点范围是实验性的,可能会被弃用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个小函数,以给定增量在两个值之间进行插值.

I'm trying to make a little function to interpolate between two values with a given increment.

[ 1.0 .. 0.5 .. 20.0 ]

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

The compiler tells me that this is deprecated, and suggests using ints then casting to float. But this seems a bit long-winded if I have a fractional increment - do I have to divide my start and end values by my increment, then multiple again afterwards? (yeuch!).

我曾在某处看到过有关使用序列推导式执行此操作的内容,但我不记得是如何做到的.

I saw something somewhere once about using sequence comprehensions to do this, but I can't remember how.

请帮忙.

推荐答案

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

TL;DR: F# PowerPack's BigRational type is the way to go.

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

As many have pointed out, float values are not suitable for looping:

  • 它们确实有舍入误差,就像十进制的1/3一样,我们不可避免地会丢失从某个指数开始的所有数字;
  • 他们确实经历了灾难性取消(当减去两个几乎相等的数字时,结果四舍五入为零);
  • 他们总是有非零的机器 epsilon,所以误差会增加数学运算(除非我们多次添加不同的数字,以便错误相互抵消——但循环并非如此);
  • 它们在整个范围内确实具有不同的准确度:范围 [0.0000001 .. 0.0000002] 中唯一值的数量等于 [1000000 .. 2000000 中唯一值的数量];
  • They do have Round Off Error, just like with 1/3 in decimal, we inevitably lose all digits starting at a certain exponent;
  • They do experience Catastrophic Cancellation (when subtracting two almost equal numbers, the result is rounded to zero);
  • They always have non-zero Machine epsilon, so the error is increased with every math operation (unless we are adding different numbers many times so that errors mutually cancel out -- but this is not the case for the loops);
  • They do have different accuracy across the range: the number of unique values in a range [0.0000001 .. 0.0000002] is equivalent to the number of unique values in [1000000 .. 2000000];

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

What can instantly solve the above problems, is switching back to integer logic.

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

With F# PowerPack, you may use BigRational type:

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

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

Note, I took my liberty to set the step to 1/3 because 0.5 from your question actually has an exact binary representation 0.1b and is represented as +1.00000000000000000000000 * 2-1; hence it does not produce any cumulative summation error.

输出:

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;

1.000000; 1.333333; 1.666667; 2.000000; 2.333333; 2.666667; 3.000000; (skipped) 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;

0.200000; 0.300000; 0.400000; 0.500000; (skipped) 2.800000; 2.900000; 3.000000;

结论

  • BigRational 使用整数计算,并不比浮点数慢
  • 对每个值只进行一次舍入(转换为 float 后,但不在循环内);
  • BigRational 就像机器 epsilon 为零一样;
  • Conclusion

    • BigRational uses integer computations, which are not slower than for floating-points;
    • The round-off occurs only once for each value (upon conversion to a float, but not within the loop);
    • BigRational acts as if the machine epsilon were zero;
    • 有一个明显的限制:你不能使用像 pisqrt(2) 这样的无理数,因为它们没有精确的分数表示.这似乎不是一个很大的问题,因为通常,我们不会遍历有理数和无理数,例如[1 .. pi/2 .. 42].如果我们这样做(例如几何计算),通常有一种方法可以减少非理性部分,例如从弧度切换到度数.

      There is an obvious limitation: you can't use irrational numbers like pi or sqrt(2) as they have no exact representation as a fraction. It does not seem to be a very big problem because usually, we are not looping over both rational and irrational numbers, e.g. [1 .. pi/2 .. 42]. If we do (like for geometry computations), there's usually a way to reduce the irrational part, e.g. switching from radians to degrees.

      进一步阅读:

      这篇关于F# 浮点范围是实验性的,可能会被弃用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆