sqrt

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 13, 2025 License: BSD-3-Clause Imports: 9 Imported by: 0

README

sqrt

A package to compute square roots and cube roots to arbitrary precision.

This package is dedicated to my mother, who taught me how to calculate square roots by hand as a child.

How this package differs from big.Float.Sqrt

big.Float.Sqrt requires a finite precision to be set ahead of time. The answer it gives is only accurate to that precision. This package does not require a precision to be set in advance. Square root values in this package compute their digits lazily on an as needed basis just as one would compute square roots by hand. Also, this package features cube roots which big.Float in the standard library does not offer as of this writing. Cube root values in this package also compute their digits lazily on an as needed basis just as one would compute cube roots by hand.

Examples

package main

import (
    "fmt"

    "github.com/keep94/sqrt"
)

func main() {

    // Print the first 1000 digits of the square root of 2.
    fmt.Printf("%.1000g\n", sqrt.Sqrt(2))

    // Print the 10,000th digit of the cube root of 5.
    fmt.Println(sqrt.CubeRoot(5).At(9999))
}

More Documentation

More documentation and examples can be found here.

Documentation

Overview

Package sqrt computes square roots and cube roots to arbitrary precision.

Number is the main type in this package. It represents a lazily evaluated non negative real number that generally has an infinite number of digits, but a Number can also have a finite number of digits.

A FiniteNumber works like Number except that it always has a finite number of digits. A *FiniteNumber can be used anywhere a Number type is expected but not the other way around.

A Sequence is a view of a contiguous subset of digits of a Number. For example, A Sequence could represent everything past the 1000th digit of the square root of 3. Because Sequences are views, they are cheap to create. Note that Number and *FiniteNumber can be used anywhere a Sequence type is expected. A Sequence can be either infinite or finite in length.

A FiniteSequence works like Sequence except unlike Sequence, a FiniteSequence is always finite in length. A FiniteSequence can be used anywhere a Sequence is expected, and a *FiniteNumber can be used anywhere a FiniteSequence is expected. However, a Number or Sequence cannot be used where a FiniteSequence is expected because they can have an infinite number of digits. A FiniteSequence must have a finite number of digits.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AsString

func AsString(s FiniteSequence) string

AsString returns all the digits in s as a string.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// sqrt(3) = 0.1732050807... * 10^1
	n := sqrt.Sqrt(3)

	fmt.Println(sqrt.AsString(n.WithStart(2).WithEnd(10)))
}
Output:

32050807

Types

type FiniteNumber

type FiniteNumber struct {
	// contains filtered or unexported fields
}

FiniteNumber is a Number with a finite number of digits. FiniteNumber implements both Number and FiniteSequence. The zero value for FiniteNumber is 0.

Pass FiniteNumber instances by reference not by value. Copying a FiniteNumber instance is not supported and may cause errors.

func NewFiniteNumber

func NewFiniteNumber(fixed []int, exponent int) (*FiniteNumber, error)

NewFiniteNumber works like NewNumberForTesting except that it returns a *FiniteNumber instead of a Number. Note that there is no repeating parameter because FiniteNumbers have a finite number of digits.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// n = 563.5
	n, _ := sqrt.NewFiniteNumber([]int{5, 6, 3, 5}, 3)

	fmt.Println(n.Exact())
}
Output:

563.5

func (*FiniteNumber) All

func (n *FiniteNumber) All() iter.Seq2[int, int]

All comes from the Sequence interface.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// sqrt(7) = 0.26457513110... * 10^1
	n := sqrt.Sqrt(7)

	for index, value := range n.All() {
		fmt.Println(index, value)
		if index == 5 {
			break
		}
	}
}
Output:

0 2
1 6
2 4
3 5
4 7
5 5

func (*FiniteNumber) AllInRange

func (n *FiniteNumber) AllInRange(start, end int) iter.Seq2[int, int]

AllInRange comes from the Sequence interface.

func (*FiniteNumber) At

func (n *FiniteNumber) At(posit int) int

At comes from the Number interface.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// sqrt(7) = 0.264575131106459...*10^1
	n := sqrt.Sqrt(7)

	fmt.Println(n.At(0))
	fmt.Println(n.At(1))
	fmt.Println(n.At(2))
}
Output:

2
6
4

func (*FiniteNumber) Backward

func (n *FiniteNumber) Backward() iter.Seq2[int, int]

Backward comes from the FiniteSequence interface.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// sqrt(7) = 0.26457513110... * 10^1
	n := sqrt.Sqrt(7).WithSignificant(6)

	for index, value := range n.Backward() {
		fmt.Println(index, value)
	}
}
Output:

5 5
4 7
3 5
2 4
1 6
0 2

func (*FiniteNumber) Exact

func (n *FiniteNumber) Exact() string

Exact works like String, but uses enough significant digits to return the exact representation of n.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {
	n := sqrt.Sqrt(2).WithSignificant(60)
	fmt.Println(n.Exact())
}
Output:

1.41421356237309504880168872420969807856967187537694807317667

func (*FiniteNumber) Exponent

func (n *FiniteNumber) Exponent() int

Exponent comes from the Number interface.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// sqrt(50176) = 0.224 * 10^3
	n := sqrt.Sqrt(50176)

	fmt.Println(n.Exponent())
}
Output:

3

func (*FiniteNumber) FiniteWithStart

func (n *FiniteNumber) FiniteWithStart(start int) FiniteSequence

FiniteWithStart comes from the FiniteSequence interface.

func (*FiniteNumber) Format

func (n *FiniteNumber) Format(state fmt.State, verb rune)

Format comes from the Number interface.

func (*FiniteNumber) IsZero

func (n *FiniteNumber) IsZero() bool

IsZero comes from the Number interface.

func (*FiniteNumber) String

func (n *FiniteNumber) String() string

String comes from the Number interface.

func (*FiniteNumber) Values

func (n *FiniteNumber) Values() iter.Seq[int]

Values comes from the Sequence interface.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {
	// sqrt(7) = 0.26457513110... * 10^1
	n := sqrt.Sqrt(7)

	for value := range n.WithEnd(6).Values() {
		fmt.Println(value)
	}
}
Output:

2
6
4
5
7
5

func (*FiniteNumber) WithEnd

func (n *FiniteNumber) WithEnd(end int) FiniteSequence

WithEnd comes from the Sequence interface.

func (*FiniteNumber) WithSignificant

func (n *FiniteNumber) WithSignificant(limit int) *FiniteNumber

WithSignificant comes from the Number interface.

func (*FiniteNumber) WithStart

func (n *FiniteNumber) WithStart(start int) Sequence

WithStart comes from the Sequence interface.

type FiniteSequence

type FiniteSequence interface {
	Sequence

	// Backward returns the 0 based position and value of each digit in this
	// FiniteSequence from end to beginning.
	Backward() iter.Seq2[int, int]

	// FiniteWithStart works like WithStart except that it returns a
	// FiniteSequence.
	FiniteWithStart(start int) FiniteSequence
}

FiniteSequence represents a Sequence of finite length.

type Generator

type Generator interface {

	// Generate returns the digits of the mantissa and the exponent for a
	// Number. Numbers are of the form mantissa*10^exp where mantissa is
	// is between 0.1 inclusive and 1.0 exclusive. Calling digits() returns
	// each digit of the mantissa in turn. The first call to digits() cannot
	// return 0 because of the range of values a mantissa can have. If a
	// call to digits() returns -1, this means that there are no more digits
	// in the mantissa. If the first call to digits() return -1, that means
	// that the resulting Number is zero. Once a call to digits() returns -1,
	// all successive calls to digits() must also return -1. digits() must
	// return values between 0 and 9 or -1.
	Generate() (digits func() int, exp int)
}

Interface Generator lazily generates the digits of a Number.

type Number

type Number interface {
	Sequence

	// At returns the significant digit of this Number at the given 0 based
	// position. If this Number has posit or fewer significant digits, At
	// returns -1. If posit is negative, At returns -1.
	At(posit int) int

	// WithSignificant returns a view of this Number that has no more than
	// limit significant digits. WithSignificant rounds the returned value
	// down toward zero. WithSignificant panics if limit is negative.
	WithSignificant(limit int) *FiniteNumber

	// Exponent returns the exponent of this Number.
	Exponent() int

	// Format prints this Number with the f, F, g, G, e, E verbs. The
	// verbs work in the usual way except that they always round down.
	// Because Number can have an infinite number of digits, g with no
	// precision shows a max of 16 significant digits. Format supports
	// width, precision, and the '-' flag for left justification. The v
	// verb is an alias for g.
	Format(state fmt.State, verb rune)

	// String returns the decimal representation of this Number using %g.
	String() string

	// IsZero returns true if this Number is zero.
	IsZero() bool
	// contains filtered or unexported methods
}

Number is a reference to a non-negative real number. A non-zero Number is of the form mantissa * 10^exponent where mantissa is between 0.1 inclusive and 1.0 exclusive. A Number can represent either a finite or infinite number of digits. A Number computes the digits of its mantissa lazily on an as needed basis. To compute a given digit, a Number must compute all digits that come before that digit. A Number stores its computed digits so that they only have to be computed once. Number instances are safe to use with multiple goroutines.

The Number factory functions such as the Sqrt and CubeRoot functions return new Number instances that contain no computed digits initially.

Because Number instances store their computed digits, it is best to reuse a Number instance when possible. For example the code:

n := sqrt.Sqrt(6)
fmt.Println(n.At(10000))
fmt.Println(n.At(10001))

runs faster than the code:

fmt.Println(sqrt.Sqrt(6).At(10000))
fmt.Println(sqrt.Sqrt(6).At(10001))

In the first code block, the second line reuses digits computed in the first line, but in the second code block, no reuse is possible since sqrt.Sqrt(6) always returns a Number with no precomputed digits.

A Number can be 0, in which case IsZero() returns true. Zero Numbers have an exponent of 0 and no digits in their mantissa. This means that calling At() on a zero Number always returns -1. Likewise calling All() or Values() on a zero Number returns an empty iterator. However, calling String() on a zero Number returns "0" and printing a zero Number prints 0 according to the format specification used.

func CubeRoot

func CubeRoot(radican int64) Number

CubeRoot returns the cube root of radican. CubeRoot panics if radican is negative as Number can only hold positive results.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// Print the cube root of 3 with 100 significant digits.
	fmt.Printf("%.100g\n", sqrt.CubeRoot(3))
}
Output:

1.442249570307408382321638310780109588391869253499350577546416194541687596829997339854755479705645256

func CubeRootBigInt

func CubeRootBigInt(radican *big.Int) Number

CubeRootBigInt returns the cube root of radican. CubeRootBigInt panics if radican is negative as Number can only hold positive results.

func CubeRootBigRat

func CubeRootBigRat(radican *big.Rat) Number

CubeRootBigRat returns the cube root of radican. Because Number can only hold positive results, the denominator of radican must be positive, and the numerator must be non-negative or else CubeRootBigRat panics.

func CubeRootRat

func CubeRootRat(num, denom int64) Number

CubeRootRat returns the cube root of num / denom. Because Number can only hold positive results, denom must be positive, and num must be non-negative or else CubeRootRat panics.

func NewNumber

func NewNumber(g Generator) Number

NewNumber returns a new Number based on g. Although g is expected to follow the contract of Generator, if g yields mantissa digits outside the range of 0 and 9, NewNumber regards that as a signal that there are no more mantissa digits. Also if g happens to yield 0 as the first digit of the mantissa, NewNumber will return zero.

func NewNumberForTesting

func NewNumberForTesting(fixed, repeating []int, exp int) (Number, error)

NewNumberForTesting creates an arbitrary Number for testing. fixed are digits between 0 and 9 representing the non repeating digits that come immediately after the decimal place of the mantissa. repeating are digits between 0 and 9 representing the repeating digits that follow the non repeating digits of the mantissa. exp is the exponent part of the returned Number. NewNumberForTesting returns an error if fixed or repeating contain values not between 0 and 9, or if the first digit of the mantissa would be zero since mantissas must be between 0.1 inclusive and 1.0 exclusive.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// n = 10.2003400340034...
	n, _ := sqrt.NewNumberForTesting([]int{1, 0, 2}, []int{0, 0, 3, 4}, 2)

	fmt.Println(n)
}
Output:

10.20034003400340

func Sqrt

func Sqrt(radican int64) Number

Sqrt returns the square root of radican. Sqrt panics if radican is negative.

Example
package main

import (
	"fmt"

	"github.com/keep94/sqrt"
)

func main() {

	// Print the square root of 13 with 100 significant digits.
	fmt.Printf("%.100g\n", sqrt.Sqrt(13))
}
Output:

3.605551275463989293119221267470495946251296573845246212710453056227166948293010445204619082018490717

func SqrtBigInt

func SqrtBigInt(radican *big.Int) Number

SqrtBigInt returns the square root of radican. SqrtBigInt panics if radican is negative.

func SqrtBigRat

func SqrtBigRat(radican *big.Rat) Number

SqrtBigRat returns the square root of radican. The denominator of radican must be positive, and the numerator must be non-negative or else SqrtBigRat panics.

func SqrtRat

func SqrtRat(num, denom int64) Number

SqrtRat returns the square root of num / denom. denom must be positive, and num must be non-negative or else SqrtRat panics.

type Sequence

type Sequence interface {

	// All returns the 0 based position and value of each digit in this
	// Sequence from beginning to end.
	All() iter.Seq2[int, int]

	// AllInRange returns the 0 based position and value of each digit in
	// this sequence from position start up to but not including position
	// end.
	AllInRange(start, end int) iter.Seq2[int, int]

	// Values returns the value of each digit in this Sequence from
	// beginning to end.
	Values() iter.Seq[int]

	// WithStart returns a view of this Sequence that only has digits with
	// zero based positions greater than or equal to start.
	WithStart(start int) Sequence

	// WithEnd returns a view of this Sequence that only has digits with
	// zero based positions less than end.
	WithEnd(end int) FiniteSequence
	// contains filtered or unexported methods
}

Sequence represents a sequence of digits of either finite or infinite length within the mantissa of a real number. Although they can start and optionally end anywhere within a mantissa, Sequences must be contiguous. That is they can have no gaps in the middle.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL