F#浮点范围是实验性的,可能会被弃用 [英] F# Floating point ranges are experimental and may be deprecated
问题描述
[1.0 ..我试图做一个小函数来在两个值之间插入一个给定的增量。 0.5 .. 20.0]
编译器告诉我这已经被弃用了,建议使用ints然后转换为浮动。但是,如果我有一个分数增量,这似乎有点啰嗦 - 我必须将我的开始和结束值除以我的增量,然后再多倍吗? ($!
$ b< p>我曾经在某个地方看到过使用序列综合的方法来做这件事,但是我不记得怎么做。 b $ b
Help,please。
TL; DR: F#PowerPack's 正如很多人指出的那样, 什么能瞬间解决上述问题,整数逻辑。 使用 F#PowerPack ,您可以使用 我自由地将步骤设置为 输出: 0.200000; 0.300000; 0.400000; 0.500000; (跳过) 2.800000; 2.900000; 3.000000; 有一个明显的限制:不能使用非理性数字如 延伸阅读: I'm trying to make a little function to interpolate between two values with a given increment. 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. Help, please. TL;DR: F# PowerPack's As many have pointed out, What can instantly solve the above problems, is switching back to integer logic. With F# PowerPack, you may use Note, I took my liberty to set the step to Outputs: 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;
Outputs: 0.200000; 0.300000; 0.400000; 0.500000; (skipped) 2.800000; 2.900000; 3.000000;
There is an obvious limitation: you can't use irrational numbers like Further reading: 这篇关于F#浮点范围是实验性的,可能会被弃用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! BigRational
类型是要走的路
点循环
float
值不适合循环:
1/3
一样,我们不可避免地丢失了所有数字从某个指数开始;
[0.0000001 .. 0.0000002]
相当于 [1000000 .. 2000000]
中唯一值的数目;
解决方案
BigRational
键入:
打开Microsoft.FSharp.Math
// [1 .. 1/3 .. 20]
[1N .. 1N / 3N .. 20N]
|> List.map float
|> List.iter(printf%f;)
1/3
,因为您的问题中的 0.5
实际上具有精确的二进制表示形式0.1 < sub> b ,表示为+1.00000000000000000000000 * 2 -1 ;因此它不会产生任何累积求和错误。
输出:
$ block $ $ b $ 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;)
结论
BigRational
使用整数计算,不比浮点
float
,但不在循环中);
BigRational
就好像机器的epsilon为零一样;
pi
或 sqrt(2)
,因为它们没有精确的表示形式。这似乎并不是一个很大的问题,因为通常我们并没有在 和之间循环。 [1 .. pi / 2 .. 42]
。如果我们这样做(比如几何计算),通常有一种方法可以减少非理性的部分,例如从弧度切换到度数。
[ 1.0 .. 0.5 .. 20.0 ]
BigRational
type is the way to go.
What's Wrong with Floating-point Loops
float
values are not suitable for looping:
1/3
in decimal, we inevitably lose all digits starting at a certain exponent;[0.0000001 .. 0.0000002]
is equivalent to the number of unique values in [1000000 .. 2000000]
;Solution
BigRational
type:open Microsoft.FSharp.Math
// [1 .. 1/3 .. 20]
[1N .. 1N/3N .. 20N]
|> List.map float
|> List.iter (printf "%f; ")
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.
// [0.2 .. 0.1 .. 3]
[1N/5N .. 1N/10N .. 3N]
|> List.map float
|> List.iter (printf "%f; ")
Conclusion
BigRational
uses integer computations, which are not slower than for floating-points;float
, but not within the loop);BigRational
acts as if the machine epsilon were zero;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.