Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement log2, log10, log256 (and possibly ln) #123

Closed
diwu1989 opened this issue Sep 28, 2022 · 13 comments
Closed

implement log2, log10, log256 (and possibly ln) #123

diwu1989 opened this issue Sep 28, 2022 · 13 comments

Comments

@diwu1989
Copy link

Can there be a natural log or base 2 log implemented?
Thanks

@A-ndy-git
Copy link

+1. Also been looking for this functionality for some time.

I'm unsure of the best method to implement this?

@elee1766
Copy link
Contributor

elee1766 commented Dec 4, 2022

there are a few different solidity libraries that implement logarithm. off the top of my head, the big name i know is oz, they have log2,log10,log256 in their math libraries: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol
log10 i think is used in their word -> ascii string function.

it may be desirable to replicate the results (not method, we can probably do better) of one such library (not neccesarily oz's), since I think mirroring or performing on-chain operations is a common use case for this package.

@diwu1989
Copy link
Author

diwu1989 commented Dec 7, 2022

+1 yes, that was my reasoning for requesting this, because I wanted to match some of the LOG math used in smart contracts

@elee1766
Copy link
Contributor

+1 yes, that was my reasoning for requesting this, because I wanted to match some of the LOG math used in smart contracts

happy to do some work on this. personally we use log2

which LOG math functions do you have immediate needs for? i can start with those and add more down the line

log2? log10? log256?

@diwu1989
Copy link
Author

Log2 is enough for UniswapV3 tickmath:
https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/TickMath.sol

@holiman
Copy link
Owner

holiman commented Mar 22, 2023

Is there any difference between Log2() and BitLen()? Because the latter exists already...

@holiman holiman changed the title Is there any way to get logarithm implemented? implement log2, log10, log256 (and possibly ln) Mar 22, 2023
@karalabe
Copy link
Contributor

Is there any difference between Log2() and BitLen()? Because the latter exists already...

Yes, BitLen is int(log2). But if you want to calculate logB(N), you need log2(N)/log2(B) with full float representation, not truncated to int.

@karalabe
Copy link
Contributor

FWIW, here's a set of log implementation for big.Int https://github.com/robpike/ivy/blob/master/value/log.go

@holiman
Copy link
Owner

holiman commented Mar 23, 2023

Possible api-methods could be

(z *Int) IntLog2( ... ) *Int
(z *Int) IntLog10( ... ) *Int

(z *Int) Log2( ... ) float64
(z *Int) Log10( ... ) float64

However, it would be simpler to just do

(z *Int) IntLog2( ... ) *Int
(z *Int) IntLog10( ... ) *Int

(z *Int) Float64() float64

Then the caller can just do math.Log2(myint.ToFloat64()) to deal in floats. The math package already has it all.

Also, in fact, the IntLog methods could return a smaller uint type, e.g. uint64, because even a log2 of a uint256 will never exceed 256 in size. So no need to return *Int.

@elee1766
Copy link
Contributor

elee1766 commented Mar 23, 2023

@diwu1989 @holiman

https://gfx.cafe/-/snippets/10#LC16

the log2 required in uniswap is just msb, so bitlen - 1

at the very least it's correct when going from tick -> sqrt price -> tick

iirc msb is always bitlen - 1. if thats the case i dont see a use in adding a dedicated msb function

@holiman
Copy link
Owner

holiman commented Mar 23, 2023

Yeah implementing Log2 and Log256 is pretty trivial, but implementing Log10 is a bit more fun.

@elee1766
Copy link
Contributor

elee1766 commented Mar 23, 2023

uniswap does log1.0001 through using uint256 as a fixed point number. perhaps that is something to consider? although computers are not evm so maybe its not as great.

holiman added a commit that referenced this issue Mar 31, 2023
Adds the following methods

```golang
// CmpUint64 compares z and x and returns:
//
//	-1 if z <  x
//	 0 if z == x
//	+1 if z >  x
func (z *Int) CmpUint64(n uint64) int 

// Log10 returns the log in base 10, floored to nearest integer.
// **OBS** This method returns '0' for '0', not `-Inf`.
func (z *Int) Log10() uint
```
The implementation of `Log10` is probably close to the optimal way. The majority of cases are handled by one lookup based on the bitlength. 

For the remaining cases, one an additional lookup is performed, a comparison, and then it is done. 

This PR adds around 2K persistent memory for lookup tables and precalculated integers. 
```
lut [257] uint8 // 257 B
pows = [60]Int         // 1920 B 
pows64 = [20]uint64 // 20*8 = 160 B
```

Ref: #123
@holiman
Copy link
Owner

holiman commented Mar 31, 2023

Log10 implemented by #136
Float64 implemented by #132

If anyone wants to add Log2 and Log256, it's welcome. Otherwise, I think most users can just use the existing BitLen. I'll close this as 'done'.

@holiman holiman closed this as completed Mar 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants