From cba63a1c6acb9512c01e438c123025e40af6e0a7 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sun, 19 Jan 2020 22:19:49 -0500 Subject: [PATCH] Update some docs --- builtins/Float.roc | 46 +++++++++++++++++++++++++++++++++------------- builtins/Int.roc | 33 +++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/builtins/Float.roc b/builtins/Float.roc index a12b927599..6aabf81c5b 100644 --- a/builtins/Float.roc +++ b/builtins/Float.roc @@ -48,16 +48,29 @@ interface Float ## See #Float.highest and #Float.lowest for the highest and ## lowest values that can be held in a #Float. ## -## Note that although the IEEE-754 specification describes the values `Infinity`, `-Infinity`, `NaN`, and `-0.0`, Roc avoids these as follows: +## Like #Int, it's possible for #Float operations to overflow and underflow +## if they exceed the bounds of #Float.highest and #Float.lowest. When this happens: ## -## * #Float.sqrt returns #(Err InvalidSqrt) when it would otherwise return `NaN`. -## * Division operations return #(Err DivByZero) when they would otherwise return `Infinity` or `-Infinity`. -## * Operations that overflow crash (just like integers do) instead of returning `Infinity` or `-Infinity`. -## Under the hood, it is possible to have a zero #Float with a negative sign. However, this implementation detail intentionally conceealed. For equality purpose, `-0.0` is treated as equivalent to `0.0`, just like the spec prescribes. However, #Str.decimal always returns `0.0` when it would otherwise return `-0.0`, and both #Num.isPositive and #Num.isNegative return #False for all zero values. The only way to detect a zero with a negative sign is to convert it to #Bytes and inspect the bits directly. -#Float : Num FloatingPoint - -## Returned in an #Err by functions like #Float.div and #Float.mod when their arguments would -## result in division by zero. Division by zero is not allowed! +## * In a development build, you'll get an assertion failure. +## * In an optimized build, you'll get [`Infinity` or `-Infinity`](https://en.wikipedia.org/wiki/IEEE_754-1985#Positive_and_negative_infinity). +## +## Although some languages treat have first-class representations for +## `-Infinity`, `Infinity`, and the special `NaN` ("not a number") +## floating-point values described in the IEEE-754, Roc does not. +## Instead, Roc treats all of these as errors. If any Float operation +## in a development build encounters one of these values, it will +## result in an assertion failure. +## +## Stll, it's possible that these values may accidentally arise in +## release builds. If this happens, they will behave according to the usual +## IEEE-754 rules: any operation involving `NaN` will output `NaN`, +## any operation involving `Infinity` or `-Infinity` will output either +## `Infinity`, `-Infinity`, or `NaN`, and `NaN` is defined to be not +## equal to itself - meaning `(x == x)` returns `False` if `x` is `NaN`. +## +## These are very error-prone values, so if you see an assertion fail in +## developent because of one of them, take it seriously - and try to fix +## the code so that it can't come up in a release! #FloatingPoint := FloatingPoint ## Returned in an #Err by #Float.sqrt when given a negative number. @@ -93,13 +106,20 @@ round = \num -> ## Other Calculations (arithmetic?) -## Divide two #Float numbers. Return `Err DivByZero` if the -## second number is zero, because division by zero is undefined in mathematics. -## -## (To divide an #Int and a #Float, first convert the #Int to a #Float using one of the functions in this module.) +## Divide two #Float numbers. ## ## `a / b` is shorthand for `Float.div a b`. ## +## Division by zero is undefined in mathematics. As such, you should make +## sure never to pass zero as the denomaintor to this function! +## +## If zero does get passed as the denominator... +## +## * In a development build, you'll get an assertion failure. +## * In a release build, the function will return `Infinity`, `-Infinity`, or `NaN` depending on the arguments. +## +## To divide an #Int and a #Float, first convert the #Int to a #Float using one of the functions in this module. +## ## >>> 5.0 / 7.0 ## ## >>> Float.div 5 7 diff --git a/builtins/Int.roc b/builtins/Int.roc index 8ba1cd3c80..58ce030c39 100644 --- a/builtins/Int.roc +++ b/builtins/Int.roc @@ -19,28 +19,45 @@ interface Int ## ## See #Int.highest and #Int.lowest for the highest and ## lowest values that can be held in an #Int. +## +## If any operation would result in an #Int that is either too big +## or too small to fit in that range (e.g. running `Int.highest + 1`), +## then the operation will *overflow* or *underflow*, respectively. +## When this happens: +## +## * In a development build, you'll get an assertion failure. +## * In a release build, you'll get [wrapping overflow](https://en.wikipedia.org/wiki/Integer_overflow#Saturated_arithmetic), which is almost always a mathematically incorrect outcome for the requested operation. +## +## As such, it's very important to design your code not to exceed these bounds! +## If you need to do math outside these bounds, consider using +## a different representation other than #Int. The reason #Int has these +## bounds is for performance reasons. #Int : Num Integer ## Arithmetic -## Divide two integers and call #Float.floor on the result. +## Divide two integers and discard any fractional part of the result. ## -## (Use #Float.div for non-flooring division.) +## Division by zero is undefined in mathematics. As such, you should make +## sure never to pass zero as the denomaintor to this function! ## -## Return `Err DivByZero` if the second integer is zero, because division by zero is undefined in mathematics. +## If zero does get passed as the denominator... ## -## `a // b` is shorthand for `Int.divFloor a b`. +## * In a development build, you'll get an assertion failure. +## * In an optimized build, the function will return 0. +## +## `a // b` is shorthand for `Int.div a b`. ## ## >>> 5 // 7 ## -## >>> Int.divFloor 5 7 +## >>> Int.div 5 7 ## -## >>> -8 // -3 +## >>> 8 // -3 ## -## >>> Int.divFloor -8 -3 +## >>> Int.div 8 -3 ## ## This is the same as the #// operator. -#divFloor : Int, Int -> Result DivByZero Int +# div : Int, Int -> Int ## Perform flooring modulo on two integers. ##