elmcraft/core-extra/2.2.0

NOTE: the latest version is 2.3.0

Float.Extra

Convenience functions for dealing with Floats.

Equality

aboutEqual : Float -> Float -> Bool

Comparing Floats with == is usually wrong, unless you basically care for reference equality, since floating point numbers often have small precision drift.

0.1 + 0.2 == 0.3 --> False

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?

(0.1 + 0.2) |> Float.Extra.aboutEqual 0.3 --> True

This value handles Infinity and NaN like so:

(1 / 0) |> Float.Extra.aboutEqual (100 / 0) --> True


(0 / 0) |> Float.Extra.aboutEqual (0 / 0) --> False

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 equalWithin and specify a tolerance that is appropriate for your usecase.

equalWithin : Float -> Float -> Float -> Bool

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
--> True

Picking 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.

Formatting Floats

toFixedDecimalPlaces : Int -> Float -> String

Fix a float value represented to a certain number of decimal places as a string.

Float.Extra.toFixedDecimalPlaces 3 0.0326232 --> "0.033"
toFixedSignificantDigits : Int -> Float -> String

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"
boundaryValuesAsUnicode : (Float -> String) -> Float -> String

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.

Ranges

range : Float -> Float -> Float -> List Float

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 result
  • List.range supports Int, whereas this uses Float
  • List.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 value

Modular arithmetic

modBy : Float -> Float -> Float

Perform 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.5

Interpolation

interpolateFrom : Float -> Float -> Float -> Float

Interpolate 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 == 8

The end value can be less than the start value:

Float.Extra.interpolateFrom 10 5 0.1 == 9.5

Parameter 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