light: make fraction parts uint64, ensuring that it is always positive (#5655)

This commit is contained in:
Callum Waters
2020-11-17 14:23:16 +01:00
committed by GitHub
parent 4e71357808
commit 909da42789
5 changed files with 45 additions and 21 deletions

View File

@@ -3,18 +3,18 @@ package math
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
)
// Fraction defined in terms of a numerator divided by a denominator in int64
// format.
// Fraction defined in terms of a numerator divided by a denominator in uint64
// format. Fraction must be positive.
type Fraction struct {
// The portion of the denominator in the faction, e.g. 2 in 2/3.
Numerator int64 `json:"numerator"`
// The value by which the numerator is divided, e.g. 3 in 2/3. Must be
// positive.
Denominator int64 `json:"denominator"`
Numerator uint64 `json:"numerator"`
// The value by which the numerator is divided, e.g. 3 in 2/3.
Denominator uint64 `json:"denominator"`
}
func (fr Fraction) String() string {
@@ -27,16 +27,22 @@ func (fr Fraction) String() string {
func ParseFraction(f string) (Fraction, error) {
o := strings.Split(f, "/")
if len(o) != 2 {
return Fraction{}, errors.New("incorrect formating: should be like \"1/3\"")
return Fraction{}, errors.New("incorrect formating: should have a single slash i.e. \"1/3\"")
}
numerator, err := strconv.ParseInt(o[0], 10, 64)
numerator, err := strconv.ParseUint(o[0], 10, 64)
if err != nil {
return Fraction{}, fmt.Errorf("incorrect formatting, err: %w", err)
}
denominator, err := strconv.ParseInt(o[1], 10, 64)
denominator, err := strconv.ParseUint(o[1], 10, 64)
if err != nil {
return Fraction{}, fmt.Errorf("incorrect formatting, err: %w", err)
}
if denominator == 0 {
return Fraction{}, errors.New("denominator can't be 0")
}
if numerator > math.MaxInt64 || denominator > math.MaxInt64 {
return Fraction{}, fmt.Errorf("value overflow, numerator and denominator must be less than %d", math.MaxInt64)
}
return Fraction{Numerator: numerator, Denominator: denominator}, nil
}

View File

@@ -23,15 +23,33 @@ func TestParseFraction(t *testing.T) {
exp: Fraction{15, 5},
err: false,
},
// test divide by zero error
{
f: "2/0",
exp: Fraction{},
err: true,
},
// test negative
{
f: "-1/2",
exp: Fraction{-1, 2},
err: false,
exp: Fraction{},
err: true,
},
{
f: "1/-2",
exp: Fraction{1, -2},
err: false,
exp: Fraction{},
err: true,
},
// test overflow
{
f: "9223372036854775808/2",
exp: Fraction{},
err: true,
},
{
f: "2/9223372036854775808",
exp: Fraction{},
err: true,
},
{
f: "2/3/4",