Skip to content

Commit

Permalink
Merge pull request #16 from goinsane/develop
Browse files Browse the repository at this point in the history
v1.7.0
  • Loading branch information
orkunkaraduman authored Oct 21, 2021
2 parents 2591d14 + 5da50ad commit 52ea5b7
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Path to sources
sonar.sources=.
sonar.exclusions=*_test.go
sonar.exclusions=**/*_test.go, examples/**/*
#sonar.inclusions=

# Path to tests
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ Please see [godoc](https://pkg.go.dev/github.com/goinsane/xmath).

To run any example, please use the command like the following:

go run examples/example1.go
cd examples/
go run example1.go

## Tests

To run all tests, please use the following command:

go test -v

To run all examples, please use the following command:

go test -v -run=^Example

To run all benchmarks, please use the following command:

go test -v -run=^Benchmark -bench=.
34 changes: 33 additions & 1 deletion big.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@ func RoundBigFloat(x *big.Float) *big.Int {
return FloorBigFloat(z.Add(z, big.NewFloat(0.5)))
}

// Int64BigInt returns the integer resulting from truncating x towards zero.
// If math.MinInt64 <= x <= math.MaxInt64, the accuracy is big.Exact.
// The result is (math.MinInt64, big.Above) for x < math.MinInt64, and (math.MaxInt64, big.Below) for x > math.MaxInt64.
func Int64BigInt(x *big.Int) (int64, big.Accuracy) {
if x.IsInt64() {
return x.Int64(), big.Exact
}
switch t := x.Sign(); {
case t < 0:
return math.MinInt64, big.Above
case t > 0:
return math.MaxInt64, big.Below
}
return 0, big.Exact
}

// Uint64BigInt returns the integer resulting from truncating x towards zero.
// If 0 <= x <= math.MaxUint64, the accuracy is big.Exact.
// The result is (0, big.Above) for x < 0, and (math.MaxUint64, big.Below) for x > math.MaxUint64.
func Uint64BigInt(x *big.Int) (uint64, big.Accuracy) {
if x.IsUint64() {
return x.Uint64(), big.Exact
}
switch t := x.Sign(); {
case t < 0:
return 0, big.Above
case t > 0:
return math.MaxUint64, big.Below
}
return 0, big.Exact
}

// IntBigRat returns the result of truncating x towards zero.
// The accuracy is big.Exact if x.IsInt(); otherwise it is big.Below or big.Above.
func IntBigRat(x *big.Rat) (*big.Int, big.Accuracy) {
Expand Down Expand Up @@ -64,7 +96,7 @@ func Int64BigRat(x *big.Rat) (int64, big.Accuracy) {

// Uint64BigRat returns the integer resulting from truncating x towards zero.
// If 0 <= x <= math.MaxUint64, the accuracy is like IntBigRat.
// The result is (math.MaxUint64, big.Below) for x > math.MaxUint64.
// The result is (0, big.Above) for x < 0, and (math.MaxUint64, big.Below) for x > math.MaxUint64.
func Uint64BigRat(x *big.Rat) (uint64, big.Accuracy) {
n, a := IntBigRat(x)
if n.IsUint64() {
Expand Down
86 changes: 86 additions & 0 deletions big_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,92 @@ func ExampleRoundBigFloat() {
// round of -9: -9
}

func ExampleInt64BigInt() {
var x *big.Int
var k int64
var acc big.Accuracy

x = big.NewInt(49)
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of %v: %v acc=%v\n", x, k, acc)

x = big.NewInt(-27)
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of %v: %v acc=%v\n", x, k, acc)

x = big.NewInt(math.MaxInt64)
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of MaxInt64=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(5))
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of MaxInt64+5=%v: %v acc=%v\n", x, k, acc)

x = big.NewInt(math.MinInt64)
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of MinInt64=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(7))
k, acc = xmath.Int64BigInt(x)
fmt.Printf("int64 of MinInt64-7=%v: %v acc=%v\n", x, k, acc)

// Output:
// int64 of 49: 49 acc=Exact
// int64 of -27: -27 acc=Exact
// int64 of MaxInt64=9223372036854775807: 9223372036854775807 acc=Exact
// int64 of MaxInt64+5=9223372036854775812: 9223372036854775807 acc=Below
// int64 of MinInt64=-9223372036854775808: -9223372036854775808 acc=Exact
// int64 of MinInt64-7=-9223372036854775815: -9223372036854775808 acc=Above
}

func ExampleUint64BigInt() {
var x *big.Int
var k uint64
var acc big.Accuracy

x = big.NewInt(49)
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of %v: %v acc=%v\n", x, k, acc)

x = big.NewInt(-27)
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of %v: %v acc=%v\n", x, k, acc)

x = big.NewInt(math.MaxInt64)
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MaxInt64=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(5))
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MaxInt64+5=%v: %v acc=%v\n", x, k, acc)

x = big.NewInt(math.MinInt64)
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MinInt64=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(7))
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MinInt64-7=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).SetUint64(math.MaxUint64)
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MaxUint64=%v: %v acc=%v\n", x, k, acc)

x = new(big.Int).Add(new(big.Int).SetUint64(math.MaxUint64), big.NewInt(3))
k, acc = xmath.Uint64BigInt(x)
fmt.Printf("uint64 of MaxUint64+3=%v: %v acc=%v\n", x, k, acc)

// Output:
// uint64 of 49: 49 acc=Exact
// uint64 of -27: 0 acc=Above
// uint64 of MaxInt64=9223372036854775807: 9223372036854775807 acc=Exact
// uint64 of MaxInt64+5=9223372036854775812: 9223372036854775812 acc=Exact
// uint64 of MinInt64=-9223372036854775808: 0 acc=Above
// uint64 of MinInt64-7=-9223372036854775815: 0 acc=Above
// uint64 of MaxUint64=18446744073709551615: 18446744073709551615 acc=Exact
// uint64 of MaxUint64+3=18446744073709551618: 18446744073709551615 acc=Below
}

func ExampleIntBigRat() {
var n *big.Int
var acc big.Accuracy
Expand Down
1 change: 1 addition & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/example_dev.go
3 changes: 2 additions & 1 deletion examples/example1.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build ignore
//go:build examples
// +build examples

package main

Expand Down
2 changes: 1 addition & 1 deletion real.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Real struct {
// Calling the NewReal, isn't necessary to create new Real.
// It panics unless base is in valid range.
func NewReal(prec, base int) *Real {
checkInvalidBase(base)
panicForInvalidBase(base)
return &Real{
prec: prec,
base: base,
Expand Down
2 changes: 1 addition & 1 deletion stepper.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Stepper struct {
// Both of max and min can be infinity. In this case, the range of Stepper is infinity.
// It panics unless base is in valid range.
func NewStepper(prec, base int, step, max, min float64) (s *Stepper, err error) {
checkInvalidBase(base)
panicForInvalidBase(base)
s = &Stepper{
prec: prec,
base: base,
Expand Down
166 changes: 158 additions & 8 deletions xmath.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ const (
MaxUint16Value = 1<<16 - 1
MaxUint32Value = 1<<32 - 1
MaxUint64Value = 1<<64 - 1
MaxIntValue = 1<<(UintSize-1) - 1
MinIntValue = -1 << (UintSize - 1)
MaxUintValue = 1<<UintSize - 1
UintSize = 32 << (^uint(0) >> 32 & 1)

MaxIntValue = 1<<(UintSize-1) - 1
MinIntValue = -1 << (UintSize - 1)
MaxUintValue = 1<<UintSize - 1

UintSize = 32 << (^uint(0) >> 32 & 1)
)

// FloorP returns the greatest value less than or equal to x with specified decimal precision.
Expand All @@ -38,7 +40,7 @@ func FloorP(x float64, prec int) float64 {
// FloorPB returns the greatest value less than or equal to x with specified precision of base.
// It panics unless base is in valid range.
func FloorPB(x float64, prec int, base int) float64 {
checkInvalidBase(base)
panicForInvalidBase(base)
k := math.Pow(float64(base), float64(prec))
return math.Floor(x*k) / k
}
Expand All @@ -52,7 +54,7 @@ func CeilP(x float64, prec int) float64 {
// CeilPB returns the least value greater than or equal to x with specified precision of base.
// It panics unless base is in valid range.
func CeilPB(x float64, prec int, base int) float64 {
checkInvalidBase(base)
panicForInvalidBase(base)
k := math.Pow(float64(base), float64(prec))
return math.Ceil(x*k) / k
}
Expand All @@ -71,7 +73,7 @@ func RoundP(x float64, prec int) float64 {
// RoundPB returns the nearest integer value, rounding half away from zero with specified precision of base.
// It panics unless base is in valid range.
func RoundPB(x float64, prec int, base int) float64 {
checkInvalidBase(base)
panicForInvalidBase(base)
k := math.Pow(float64(base), float64(prec))
return math.Floor(x*k+0.5) / k
}
Expand Down Expand Up @@ -585,8 +587,156 @@ func IsZero(x float64) bool {
return math.Float64bits(x)<<12 == 0
}

func checkInvalidBase(base int) {
// Zero returns zero floating point value by given sign.
// -0.0 if sign < 0
// +0.0 if sign is 0
// +0.0 if sign > 0
func Zero(sign int) float64 {
return math.Copysign(0, float64(sign))
}

// Sign returns:
// -1 if x < 0
// 0 if x is ±0
// +1 if x > 0
// Sign panics if x is NaN.
func Sign(x float64) int {
if math.IsNaN(x) {
panicForNaN(x)
}
switch {
case x < 0:
return -1
case x > 0:
return 1
}
return 0
}

// SignInt returns:
// -1 if x < 0
// 0 if x is 0
// +1 if x > 0
func SignInt(x int64) int {
switch {
case x < 0:
return -1
case x > 0:
return 1
}
return 0
}

// Sum returns the sum of x...
func Sum(x ...float64) (sum float64) {
for _, y := range x {
sum += y
}
return
}

// Avg returns the arithmetic mean of x...
func Avg(x ...float64) (avg float64) {
k := float64(len(x))
for _, y := range x {
avg += y / k
}
return
}

// SumInt returns the floating point of sum of x...
func SumInt(x ...int64) (sum float64) {
for _, y := range x {
sum += float64(y)
}
return
}

// AvgInt returns the floating point of arithmetic mean of x...
func AvgInt(x ...int64) (avg float64) {
k := float64(len(x))
for _, y := range x {
avg += float64(y) / k
}
return
}

// SumUint returns the floating point of sum of x...
func SumUint(x ...uint64) (sum float64) {
for _, y := range x {
sum += float64(y)
}
return
}

// AvgUint returns the floating point of arithmetic mean of x...
func AvgUint(x ...uint64) (avg float64) {
k := float64(len(x))
for _, y := range x {
avg += float64(y) / k
}
return
}

// SumInt2 returns the sum of x...
// If the result overflows, it returns overflow is true.
func SumInt2(x ...int64) (sum int64, overflow bool) {
var last int64
for _, y := range x {
sum += y
signLast, signSum, signY := SignInt(last), SignInt(sum), SignInt(y)
if !overflow && signLast != signSum && signLast == signY {
overflow = true
}
last = sum
}
return
}

// AvgInt2 returns the arithmetic mean of x...
// If the result overflows, it returns overflow is true.
func AvgInt2(x ...int64) (avg int64, overflow bool) {
var sum int64
sum, overflow = SumInt2(x...)
if count := len(x); count > 0 {
avg = sum / int64(count)
}
return
}

// SumUint2 returns the sum of x...
// If the result overflows, it returns overflow is true.
func SumUint2(x ...uint64) (sum uint64, overflow bool) {
var last uint64
for _, y := range x {
sum += y
if !overflow && sum < last {
overflow = true
}
last = sum
}
return
}

// AvgUint2 returns the arithmetic mean of x...
// If the result overflows, it returns overflow is true.
func AvgUint2(x ...uint64) (avg uint64, overflow bool) {
var sum uint64
sum, overflow = SumUint2(x...)
if count := len(x); count > 0 {
avg = sum / uint64(count)
}
return
}

func panicForInvalidBase(base int) {
if base < MinBase || base > MaxBase {
panic("invalid base")
}
}

func panicForNaN(x float64) {
if math.IsNaN(x) {
panic("NaN value")
}
}
Loading

0 comments on commit 52ea5b7

Please sign in to comment.