diff --git a/docs/sophia_stdlib.md b/docs/sophia_stdlib.md index 3b83666..06357f4 100644 --- a/docs/sophia_stdlib.md +++ b/docs/sophia_stdlib.md @@ -32,6 +32,7 @@ Sophia language offers standard library that consists of following namespaces: - [Pair](#Pair) - [Triple](#Triple) - [BLS12_381](#BLS12_381) +- [Frac](#Frac) # Builtin namespaces @@ -1618,3 +1619,216 @@ BLS12_381.final_exp(p : gt) : gt ``` Perform the final exponentiation step of pairing for a `gt` value. + +## Frac + +This namespace provides operations on rational numbers. A rational number is represented +as a fraction of two integers which are stored internally in the `frac` datatype. + +The datatype consists of three constructors `Neg/2`, `Zero/0` and `Pos/2` which determine the +sign of the number. Both values stored in `Neg` and `Pos` need to be strictly positive +integers. However, when creating a `frac` you should never use the constructors explicitly. +Instead of that, always use provided functions like `make_frac` or `from_int`. This helps +keeping the internal representation in a good form. + +The described below functions take care of normalization of the fractions – +they won't grow if it is unnecessary. Please note that the size of `frac` can be still +very big while the value is actually very close to a natural number – the division of +two extremely big prime numbers *will* be as big as both of them. To face this issue +the [optimize](#optimize) function is provided. It will approximate the value of the +fraction to fit in the given error margin and to shrink its size as much as possible. + +### make_frac +`Frac.make_frac(n : int, d : int) : frac` + +Creates a fraction out of numerator and denominator. Automatically normalizes, so +`make_frac(2, 4)` and `make_frac(1, 2)` will yield same results. + + +### num +`Frac.num(f : frac) : int` + +Returns the numerator of a fraction. + + +### den +`Frac.den(f : frac) : int` + +Returns the denominator of a fraction. + + +### to_pair +`Frac.to_pair(f : frac) : int * int` + +Turns a fraction into a pair of numerator and denominator. + + +### sign +`Frac.sign(f : frac) : int` + +Returns the signum of a fraction, -1, 0, 1 if negative, zero, positive respectively. + + +### to_str +`Frac.to_str(f : frac) : string` + +Conversion to string. Does not display division by 1 or denominator if equals zero. + + +### simplify +`Frac.simplify(f : frac) : frac` + +Reduces fraction to normal form if for some reason it is not in it. + + +### eq +`Frac.eq(a : frac, b : frac) : bool` + +Checks if `a` is equal to `b`. + + +### neq +`Frac.neq(a : frac, b : frac) : bool` + +Checks if `a` is not equal to `b`. + + +### geq +`Frac.geq(a : frac, b : frac) : bool` + +Checks if `a` is greater or equal to `b`. + + +### leq +`Frac.leq(a : frac, b : frac) : bool` + +Checks if `a` is lesser or equal to `b`. + + +### gt +`Frac.gt(a : frac, b : frac) : bool` + +Checks if `a` is greater than `b`. + + +### lt +`Frac.lt(a : frac, b : frac) : bool` + +Checks if `a` is lesser than `b`. + + +### min +`Frac.min(a : frac, b : frac) : frac` + +Chooses lesser of the two fractions. + + +### max +`Frac.max(a : frac, b : frac) : frac` + +Chooses greater of the two fractions. + + +### abs +`Frac.abs(f : frac) : frac` + +Absolute value. + + +### from_int +`Frac.from_int(n : int) : frac` + +From integer conversion. Effectively `make_frac(n, 1)`. + + +### floor +`Frac.floor(f : frac) : int` + +Rounds a fraction to the nearest lesser or equal integer. + + +### ceil +`Frac.ceil(f : frac) : int` + +Rounds a fraction to the nearest greater or equal integer. + + +### round_to_zero +`Frac.round_to_zero(f : frac) : int` + +Rounds a fraction towards zero. +Effectively `ceil` if lesser than zero and `floor` if greater. + + +### round_from_zero +`Frac.round_from_zero(f : frac) : int` + +Rounds a fraction from zero. +Effectively `ceil` if greater than zero and `floor` if lesser. + + +### round +`Frac.round(f : frac) : int` + +Rounds a fraction to a nearest integer. If two integers are in the same distance it +will choose the even one. + + +### add +`Frac.add(a : frac, b : frac) : frac` + +Sum of the fractions. + + +### neg +`Frac.neg(a : frac) : frac` + +Negation of the fraction. + + +### sub +`Frac.sub(a : frac, b : frac) : frac` + +Subtraction of two fractions. + + +### inv +`Frac.inv(a : frac) : frac` + +Inverts a fraction. Throws error if `a` is zero. + + +### mul +`Frac.mul(a : frac, b : frac) : frac` + +Multiplication of two fractions. + + +### div +`Frac.div(a : frac, b : frac) : frac` + +Division of two fractions. + + +### int_exp +`Frac.int_exp(b : frac, e : int) : frac` + +Takes `b` to the power of `e`. The exponent can be a negative value. + + +### optimize +`Frac.optimize(f : frac, loss : frac) : frac` + +Shrink the internal size of a fraction as much as possible by approximating it to the +point where the error would exceed the `loss` value. + + +### is_sane +`Frac.is_sane(f : frac) : bool` + +For debugging. If it ever returns false in a code that doesn't call `frac` constructors or +accept arbitrary `frac`s from the surface you should report it as a +[bug](https://github.com/aeternity/aesophia/issues/new) + +If you expect getting calls with malformed `frac`s in your contract, you should use +this function to verify the input. diff --git a/priv/stdlib/Frac.aes b/priv/stdlib/Frac.aes index 1fdebb5..37ef80f 100644 --- a/priv/stdlib/Frac.aes +++ b/priv/stdlib/Frac.aes @@ -62,17 +62,13 @@ namespace Frac = else simplify(Neg(abs_int(n), abs_int(d))) function eq(a : frac, b : frac) : bool = - let na = num(a) - let nb = num(b) - let da = den(a) - let db = den(b) + let (na, da) = to_pair(a) + let (nb, db) = to_pair(b) (na == nb && da == db) || na * db == nb * da // they are more likely to be normalized function neq(a : frac, b : frac) : bool = - let na = num(a) - let nb = num(b) - let da = den(a) - let db = den(b) + let (na, da) = to_pair(a) + let (nb, db) = to_pair(b) (na != nb || da != db) && na * db != nb * da function geq(a : frac, b : frac) : bool = num(a) * den(b) >= num(b) * den(a) @@ -131,10 +127,8 @@ namespace Frac = else cl function add(a : frac, b : frac) : frac = - let na = num(a) - let nb = num(b) - let da = den(a) - let db = den(b) + let (na, da) = to_pair(a) + let (nb, db) = to_pair(b) if (da == db) make_frac(na + nb, da) else make_frac(na * db + nb * da, da * db)