onflow / cadence

Cadence, the resource-oriented smart contract programming language šŸƒā€ā™‚ļø
https://developers.flow.com/cadence
Apache License 2.0
526 stars 136 forks source link

Request for additional math functions: ln(x), log(x,b), pow(x,y), sqrt(x), exp(x) #1151

Open figs999 opened 2 years ago

figs999 commented 2 years ago

Issue To Be Solved

Currently cadence does not support any mathematical operations more advanced than basic arithmetic. When making bonded curves or proportional staking calculations, additional operations are required.

Suggested Solution

Please add the following mathematical functions: ln(x), log(x,b), pow(x,y), sqrt(x), exp(x) Natural Logarithm, Logarithm with arbitrary base, power (x to the y), square root, and exponent (euler's-number to the x)

Functions needed for all applicable numeric types. Currently these functions are being implemented in cadence script by developers, which adds needless overhead to execution and introduces the risk of bugs in the math algorithms. It would be more efficient for the script execution runtime to use the math operators available in it's base language.

These would ideally be accessible as language built-in-functions, but could also be placed inside the Numeric types like min and max.

Pow(x,y) could be implemented via an operator, such as in other languages using "x^y" or "x**y".

darkdrag00nv2 commented 4 months ago

@turbolent

I think exp(x) is not that useful. The return type of exp(x) has to be UFix64 whose maximum value is 184467440737.09551616.

loge(184467440737.09551616) = 25.940738811884

So exp(x) would only work for x <= 25.940738811884 which won't be that useful.

Similar logic for pow(x,y) if the return type is a UFix64. So, we should probably restrict it to just integers base and exponents and keep the return type as Int.

turbolent commented 4 months ago

Yeah, we might want to consider adding larger fixed-point types (128, 256, ...), potentially even without a min/max and just a fixed scale ("UFix"/"Fix", like UInt and Int - question is what the scale would be).

darkdrag00nv2 commented 4 months ago

yeah, agreed.

Do you see any issues in making the scale flexible for UFix as well? Apart from it no longer being "Fixed point" :slightly_smiling_face:

Kind of like how big.Float allows SetPrec. Can have an upper limit on the scale such as 16 or 32 to ensure the computations are feasible.

let a = UFix.fromString("10000000000000.22222222", /*scale*/ 16);

For computation with different scales - say adding a UFix with scale 8 with another with scale 16, we could choose the larger one.

turbolent commented 4 months ago

Yeah, I guess that makes sense. It would be best to not reinvent the wheel here and find an existing design and implementation we could follow.

darkdrag00nv2 commented 4 months ago

Solidity seems to have something similar - ufixedMxN and fixedMxN where M is the total number of bits and N is the scale: https://docs.soliditylang.org/en/latest/types.html#fixed-point-numbers.

Very early stage though and not available for any practical use yet.

M must be divisible by 8 and goes from 8 to 256 bits. N must be between 0 and 80, inclusive.

So they don't think users need more than 256 bits.

I couldn't find any other fixed point implementation.


I think we can do the following:

Similarly for Fix*.