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

RRR4R: rational -> decimal #1819

Merged
merged 54 commits into from
Aug 15, 2018
Merged

RRR4R: rational -> decimal #1819

merged 54 commits into from
Aug 15, 2018

Conversation

rigelrozanski
Copy link
Contributor

@rigelrozanski rigelrozanski commented Jul 25, 2018

closes #1807

  • Linked to github-issue with discussion and accepted design
  • Updated all relevant documentation (docs/)
  • Updated all relevant code comments
  • Wrote tests
  • Added entries in PENDING.md
  • Updated cmd/gaia and examples/

For Admin Use:

  • Added appropriate labels to PR (ex. wip, ready-for-review, docs)
  • Reviewers Assigned
  • Squashed all commits, uses message "Merge pull request #XYZ: [title]" (coding standards)

@codecov
Copy link

codecov bot commented Jul 25, 2018

Codecov Report

Merging #1819 into develop will not change coverage.
The diff coverage is 78.68%.

@@           Coverage Diff            @@
##           develop    #1819   +/-   ##
========================================
  Coverage    64.86%   64.86%           
========================================
  Files          115      115           
  Lines         6862     6862           
========================================
  Hits          4451     4451           
  Misses        2127     2127           
  Partials       284      284

types/decimal.go Outdated
// nolint - go-cyclo
// Remove a Precision amount of rightmost digits and perform bankers rounding
// on the remainder (gaussian rounding) on the digits which have been removed.
func ChopPrecisionAndRound(d *big.Int) (chopped *big.Int) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should make a mutative variant of this function to use internally. We can just write a TODO / make an issue for this. (The functions here don't need to allocate different memory for chopped after computing the result)

Copy link
Contributor

Choose a reason for hiding this comment

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

Does it have to be publicly exposed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah it doesn't need to be exposed - updated this func to mutate d now

types/decimal.go Outdated

//zerosToAdd := int64(lenRem - 1 + leadingZeros)
//multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil)
//fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to keep this code, or should we delete it? If we want it kept, lets leave a comment explaining what it is. I'm partial to not keeping commented out code, but thats nbd

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, git has history, we don't need to keep comments

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah meant to delete - this should just be deleted never need it again

types/decimal.go Outdated
chopped = quo
return
case 1:
chopped = quo.Add(quo, big.NewInt(1))
Copy link
Contributor

Choose a reason for hiding this comment

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

We should cache the one

Copy link
Contributor

Choose a reason for hiding this comment

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

++

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cached (and the one below)

Copy link
Contributor

@ValarDragon ValarDragon left a comment

Choose a reason for hiding this comment

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

LGTM, made a couple efficiency suggestions, but I think we can write them up into an issue and address later.

@ValarDragon
Copy link
Contributor

Also do we want to align / rename int /uint's NewIntWithDecimal functions? I'd prefer to actually just remove those methods, and have the caller do them.

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Minor nits

types/decimal.go Outdated

// first extract any negative symbol
neg := false
if string(str[0]) == "-" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we just compare the character directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed

types/decimal.go Outdated

//zerosToAdd := int64(lenRem - 1 + leadingZeros)
//multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil)
//fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier)
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, git has history, we don't need to keep comments

types/decimal.go Outdated
chopped = quo
return
case 1:
chopped = quo.Add(quo, big.NewInt(1))
Copy link
Contributor

Choose a reason for hiding this comment

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

++

types/decimal.go Outdated
// wraps d.MarshalText()
func (d Dec) MarshalAmino() (string, error) {
if d.Int == nil {
d.Int = new(big.Int)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we return a constant string here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

confused - expand?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As in use a constant string to represent the nil case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and then manually load for this custom nil case in UnmarshalAmino?

Copy link
Contributor

Choose a reason for hiding this comment

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

That is what he was suggesting AFAICT.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

k - addressed - just define the zero values once now above

types/decimal.go Outdated
// MarshalJSON defines custom encoding scheme
func (d Dec) MarshalJSON() ([]byte, error) {
if d.Int == nil {
d.Int = new(big.Int)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we return a constant string here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed

Copy link
Contributor

@melekes melekes left a comment

Choose a reason for hiding this comment

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

Did a shallow review. LGTM. Would love to see this tested with something like https://github.com/dvyukov/go-fuzz. I can help with that.

types/decimal.go Outdated
//
// NOTE an error will return if more decimal places
// are provided in the string than the constant Precision
func NewDecFromStr(str string) (d Dec, err Error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

add a note saying we're mutating the str argument OR create a copy of str

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed - this does not modify the string (or copy it even)

types/decimal.go Outdated

combined, ok := new(big.Int).SetString(combinedStr, 10)
if !ok {
return d, ErrUnknownRequest("bad string to integer conversion")
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to print combinedStr here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

k done

types/decimal.go Outdated
}

if lenDecs > Precision {
return d, ErrUnknownRequest("too much Precision in decimal")
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to include Precision (10) here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup added that and the lenDec now

"testing"
)

// NOTE: never use new(Dec) or else we will panic unmarshalling into the
Copy link
Contributor

Choose a reason for hiding this comment

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

why not make the type private then?

Copy link
Contributor

Choose a reason for hiding this comment

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

Concrete structs get a bit better efficiency than interfaces. (Also follows the stdlib's standard)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

k just leaving for now

types/decimal.go Outdated
// nolint - go-cyclo
// Remove a Precision amount of rightmost digits and perform bankers rounding
// on the remainder (gaussian rounding) on the digits which have been removed.
func ChopPrecisionAndRound(d *big.Int) (chopped *big.Int) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it have to be publicly exposed?

types/decimal.go Outdated
mul.Mul(mul, precisionReuse)

quo := new(big.Int).Quo(mul, d2.Int)
chopped := ChopPrecisionAndRound(quo)
Copy link
Contributor

Choose a reason for hiding this comment

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

what about this check?

if chopped.BitLen() > 255+DecimalPrecisionBytes {
		panic("Int overflow")
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks - added

}

// intended to be used with require/assert: require.True(DecEq(...))
func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe move it to _test.go file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cannot, see: #1819 (comment)

@rigelrozanski
Copy link
Contributor Author

@melekes @ValarDragon @cwgoes - all comments addressed
still waiting for any comments by @jaekwon


// get the trucated quotient and remainder
quo, rem := big.NewInt(0), big.NewInt(0)
quo, rem = quo.QuoRem(d, precisionReuse, rem)
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually don't need to use quo here, it can just be d, and then quo never had to be allocated :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cool I'm going to make quo, rem := d, big.NewInt(0) just to keep it explicit - makes the return statements more clear too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay - turns out this causes a few undesired side effects because often this function is expected to return a new decimal not modify the original - I'm going to leave as is for now, I feel like this is a pretty minor optimization - but feel free to make the modification and add the fixes (a bunch of lcd stuff fails)

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure! I'll look into this more once we get get the main PR merged!

types/decimal.go Outdated

// bytes required to represent the above precision
// ceil(log2(9999999999))
DecimalPrecisionBytes = 34
Copy link
Contributor

Choose a reason for hiding this comment

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

DecimalPrecisionBits?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks, addressed

types/decimal.go Outdated
return multiplier
}

// get the precision multiplier. Do not mutate result.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a way to make Dec immutable so we can enforce it?

Copy link
Contributor

@ValarDragon ValarDragon Aug 14, 2018

Choose a reason for hiding this comment

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

These are only used within this file, so we don't need to add a separate method to enforce immutability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

leaving for now

types/decimal.go Outdated
//nolint
func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero
func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 }
func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than
Copy link
Contributor

Choose a reason for hiding this comment

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

I always use comparisons to zero, since the direction of comparison works on the values themselves.
(d.Int).Cmp(d2.Int) > 0 means d.Int > d2.Int, imo easier to grok visually.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup I like it changed

// | | __
// | | | __|__|__
// |_____: / | $$$ |
// |________|
Copy link
Contributor

Choose a reason for hiding this comment

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

lul.

@rigelrozanski rigelrozanski merged commit d9dc061 into develop Aug 15, 2018
@rigelrozanski rigelrozanski deleted the rigel/decimal branch August 15, 2018 00:15
@rigelrozanski
Copy link
Contributor Author

Merging - we can make further optimizations / adjustments in future PRs

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

Successfully merging this pull request may close these issues.

types: Switch from rational usage to decimal
8 participants