Convenience functions for dealing with Floats.
Check if two values are equal within a given (absolute) tolerance.
Float.Extra.equalWithin 1.0e-6 1.9999 2.0001
--> False
Float.Extra.equalWithin 1.0e-3 1.9999 2.0001
--> TruePicking a tolerance
equalWithin uses an absolute tolerance, meaning that the absolute difference between the two values should not exceed the tolerance.
As such, you should choose a number based on the overall magnitude of the domain you are computing in. For instance,
in a geometrical context, you can pick a value based on the size of the overall bounding box.
If measuring sizes of people, perhaps you can pick a value based on the tallest person alive, etc. In that context,
you may consider two persons equally tall, if they have the same number of millimeters in height.
Fix a float value represented to a certain number of decimal places as a string.
Float.Extra.toFixedDecimalPlaces 3 0.0326232 --> "0.033"Fix a float value represented as a string to a certain number of significant digits.
Float.Extra.toFixedSignificantDigits 2 1.435 --> "1.4"
Float.Extra.toFixedSignificantDigits 2 545435 --> "550000"
Float.Extra.toFixedSignificantDigits 2 0.0039 --> "0.0039"When showing Float values to users, we generally don't particularly want them to see programmer-y values like
NaN or Infinity. This function wraps a number formatting routine, but replaces those values with unicode symbols:
format : Float -> String
format =
Float.Extra.toFixedSignificantDigits 3
|> Float.Extra.boundaryValuesAsUnicode
format (0 / 0) --> "∅"
format (1 / 0) --> "∞"
format (-1 / 0) --> "-∞"
format (1 / 3) -> "0.333"Of course using this is unsuitable for when you want the numbers to be machine readable.
Returns a List containing an arithmetic progression, similar to the Python built-in range.
Takes a start, stop and step argument. The stop value is exclusive; it is not
included in the result. If step is positive, the last element is the largest
start + i * step less than stop; if step is negative, the last element is
the smallest start + i * step greater than stop. If the returned list would
contain an infinite number of values, an empty range is returned.
The arguments are not required to be whole numbers; however, the results are more predictable if they are.
Differences from List.range from the standard library:
List.range is inclusive, meaning that the stop value will be included in the resultList.range supports Int, whereas this uses FloatList.range supports only increasing intervals (i.e. List.range 3 1 == [] vs. range 3 1 -1 == [3, 2])List.range doesn't allow for specifying the step valuePerform modular arithmetic involving floating point numbers.
The sign of the result is the same as the sign of the modulus
in Float.Extra.modBy modulus x.
Float.Extra.modBy 2.5 5 --> 0
Float.Extra.modBy 2 4.5 == 0.5
Float.Extra.modBy 2 -4.5 == 1.5
Float.Extra.modBy -2 4.5 == -1.5Interpolate from the first value to the second, based on a parameter that ranges from zero to one. Passing a parameter value of zero will return the start value and passing a parameter value of one will return the end value.
Float.Extra.interpolateFrom 5 10 0 == 5
Float.Extra.interpolateFrom 5 10 1 == 10
Float.Extra.interpolateFrom 5 10 0.6 == 8The end value can be less than the start value:
Float.Extra.interpolateFrom 10 5 0.1 == 9.5Parameter values less than zero or greater than one can be used to extrapolate:
Float.Extra.interpolateFrom 5 10 1.5 == 12.5
Float.Extra.interpolateFrom 5 10 -0.5 == 2.5
Float.Extra.interpolateFrom 10 5 -0.2 == 11
Comparing Floats with
==is usually wrong, unless you basically care for reference equality, since floating point numbers often have small precision drift.This function implements an approximation where we are asking - are these values close enough that we can consider their difference to be due to floating point drift rather than a result of meaningful difference in calculation?
This value handles Infinity and NaN like so:
Warning: This function is handy for casual usecases, where floats are giving you some modest trouble. But for serious usecases, you should transition to using
equalWithinand specify a tolerance that is appropriate for your usecase.