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

Introduce Sqrt on NumberType #3055

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

darkdrag00nv2
Copy link
Contributor

@darkdrag00nv2 darkdrag00nv2 commented Jan 28, 2024

Work towards #1151

Description

Introduce Sqrt on NumberType defined in a Math contract.

Sqrt<T: NumberType>(value : T) : UFix64
  1. Panics with UnderflowError if value < 0.
  2. Panics with OverflowError if the result does not fit in a UFix64.

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work
  • Code follows the standards mentioned here
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Copy link

codecov bot commented Jan 28, 2024

Codecov Report

Attention: Patch coverage is 75.59055% with 31 lines in your changes are missing coverage. Please review.

Project coverage is 80.68%. Comparing base (a676d8f) to head (b2f799b).
Report is 495 commits behind head on master.

Files Patch % Lines
runtime/interpreter/value.go 38.09% 26 Missing ⚠️
runtime/interpreter/big.go 90.32% 2 Missing and 1 partial ⚠️
runtime/stdlib/math.go 96.22% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3055      +/-   ##
==========================================
+ Coverage   80.59%   80.68%   +0.08%     
==========================================
  Files         379      380       +1     
  Lines       91159    91659     +500     
==========================================
+ Hits        73472    73957     +485     
+ Misses      15053    15052       -1     
- Partials     2634     2650      +16     
Flag Coverage Δ
unittests 80.68% <75.59%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@darkdrag00nv2
Copy link
Contributor Author

Haven't added any tests yet. Opened it up for some early feedback.

  • Are we okay with making this a top level function in the standard library?
  • Does the implementation look correct? Mainly the BigIntSqrt function in the runtime/interpreter/big.go file.
  • Should we return a Optional and return Nil in case of overflows.

@turbolent
Copy link
Member

Nice work!

  • Are we okay with making this a top level function in the standard library?

Maybe we can introduce a Math library/contract? (similar to existing RLP, BLS, Crypto, etc.; similar to how there's a "math" package in some languages).
Alternatively we can also define it as a function on all Number types, as .squareRoot() (how e.g. Swift does it: https://developer.apple.com/documentation/swift/double/squareroot())

@darkdrag00nv2
Copy link
Contributor Author

@turbolent I like both the ideas.

@SupunS @dsainati1 Do you have opinions? I'll go with a separate math contract if both seem fine to you all.

@dsainati1
Copy link
Contributor

A Math contract seems the most appropriate to me

@darkdrag00nv2 darkdrag00nv2 marked this pull request as ready for review February 5, 2024 14:45
runtime/interpreter/big.go Show resolved Hide resolved
runtime/interpreter/big.go Show resolved Hide resolved
runtime/interpreter/big.go Outdated Show resolved Hide resolved
runtime/interpreter/big.go Outdated Show resolved Hide resolved
Copy link
Member

@AlexHentschel AlexHentschel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am less familiar with fixed point numbers, so my confusion maybe it is just my lack of context. Nevertheless, it might be useful to add some documentation making it easier for other people reading to code to follow, even if they are not experts in fixed-point number arithmetics. Please see my suggestions above (specifically this and this comment)

@darkdrag00nv2
Copy link
Contributor Author

Thanks for the review comments @AlexHentschel. Have incorporated your comments. PTAL again, thanks!

Copy link
Member

@AlexHentschel AlexHentschel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

@tarakby tarakby self-requested a review April 8, 2024 22:50
Copy link
Contributor

@tarakby tarakby left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work and nice documentation 👌🏼
I left a few comments below.


func BigIntSqrt(interpreter *Interpreter, value *big.Int, locationRange LocationRange) UFix64Value {
if value.Sign() < 0 {
panic(UnderflowError{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike the overflow case where the result can't fit into the target type, this case corresponds to an "undefined" case rather than an underflow. The square root being non defined for negative inputs (similar to the division by zero error where dividing by zero isn't mathematically defined).

There doesn't seem to be an "undefined" error available so I see why underflow was used, but I wanted to mention this.

// This is because of the above check with sema.MaxSquareIntegerBig.
valueFloat := new(big.Float).SetPrec(256).SetInt(value)
res := new(big.Float).SetPrec(256).SetMode(big.ToZero).Sqrt(valueFloat)
res.Mul(res, new(big.Float).SetPrec(256).SetInt(sema.Fix64FactorBig))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new(big.Float).SetPrec(256).SetInt(Fix64FactorBig) could be a global constant defined like Fix64FactorBig.

func (v Fix64Value) Sqrt(interpreter *Interpreter, locationRange LocationRange) UFix64Value {
val := new(big.Int).SetUint64(uint64(v))
sqrtWithFix64FactorSqrt := BigIntSqrt(interpreter, val, locationRange)
sqrt := sqrtWithFix64FactorSqrt / fixedpoint.Fix64FactorSqrt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible optimization: I think we can save this division if in the function BigIntSqrt (L163), we multiply by Fix64FactorSqrt instead of Fix64Factor, only in the case of Fix64Value and UFix64Value. For the rest of the types, we can keep multiplying by Fix64Factor.

// So we can support Sqrt till 34028236692093846346337 since
// Sqrt(34028236692093846346337) = 184467440737.09551615999875115311
// which gets rounded down to 184467440737.09551615
// Sqrt(34028236692093846346338) = 184467440737.09551616000146165854
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌🏼

})
}

if value.Cmp(sema.MaxSquareIntegerBig) == 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When calling this check in the case of Fix64Value and UFix64Value, I think we would exclude some values because value is larger than the max, but in reality it represents a number less than max (because value is multiplied by the factor). Actually, I think all Fix64 and UFix64 values are less than the max, so the result (square root) can always fit.

If I didn't miss anything and my comment makes sense, it may be better to have a specific function BigIntSqrtFloat to process the case of UFix64 and Fix64 skipping the overflow (also to add the optimization from my previous comment)

@SupunS SupunS added the Feature label Apr 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants