gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 21:55:29 24 4
gpt4 key购买 nike

我正在尝试创建一个小函数,以在给定增量的两个值之间进行插值。

[ 1.0 .. 0.5 .. 20.0 ]

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

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

请帮忙。

最佳答案

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

浮点循环有什么问题

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

  • 他们确实有舍入误差,就像 1/3 一样在十进制中,我们不可避免地会丢失从某个指数开始的所有数字;
  • 他们确实经历了灾难性取消(当减去两个几乎相等的数字时,结果四舍五入为零);
  • 他们总是有非零 Machine 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.1b 并表示为 +1.00000000000000000000000 * 2-1;因此它不会产生任何累积求和误差。

    输出:

    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; (skipped) 2.800000; 2.900000; 3.000000;



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

  • 有一个明显的限制:你不能使用像 pi 这样的无理数。或 sqrt(2)因为它们没有精确的分数表示。这似乎不是一个很大的问题,因为通常,我们不会同时遍历有理数和无理数,例如 [1 .. pi/2 .. 42] .如果我们这样做(例如几何计算),通常有一种方法可以减少非理性部分,例如从弧度切换到度数。

    进一步阅读:
  • What Every Computer Scientist Should Know About Floating-Point Arithmetic
  • Numeric types in PowerPack
  • 关于F# 浮点范围是实验性的,可能会被弃用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/377078/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com