Тип big.Rat

Тип big.Rat представляет собой рациональное число в виде дроби p/q, где p и q - целые числа, а q не равно нулю. Он позволяет выполнять арифметические операции с числами любой точности без потери точности, что особенно важно при работе с дробными значениями, где требуется высокая точность вычислений. В отличие от float64, big.Rat не подвержен ошибкам округления при выполнении операций деления.

Создание и инициализация

Для создания нового рационального числа используется функция big.NewRat. Она принимает два параметра: числитель (a) и знаменатель (b). Число представляется в виде a/b.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := big.NewRat(3, 4)
  fmt.Println(r)
}

Результат выполнения кода:

go3/4

Также можно создать нулевое рациональное число с помощью new(big.Rat), которое представляет собой 0/1.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := new(big.Rat)
  fmt.Println(r)
}

Результат выполнения кода:

go0/1

Для установки значения из строки используется метод SetString. Он принимает строку в формате "a/b" и возвращает само число, а также булево значение, указывающее на успешность разбора.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := new(big.Rat)
  _, ok := r.SetString("5/8")
  if ok {
    fmt.Println(r)
  }
}

Результат выполнения кода:

go5/8

Метод SetFrac позволяет установить значение рационального числа из двух целых чисел big.Int, представляющих числитель и знаменатель.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  num := big.NewInt(7)
  den := big.NewInt(12)
  r := new(big.Rat).SetFrac(num, den)
  fmt.Println(r)
}

Результат выполнения кода:

go7/12

Метод SetFloat64 создает рациональное число из значения типа float64. Он возвращает булево значение, указывающее на то, было ли преобразование точным.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := new(big.Rat)
  ok := r.SetFloat64(0.375)
  if ok {
    fmt.Println(r)
  }
}

Результат выполнения кода:

go3/8

Арифметические операции

Тип big.Rat поддерживает основные арифметические операции: сложение, вычитание, умножение и деление. Все методы изменяют приемник и возвращают его же.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r1 := big.NewRat(1, 3)
  r2 := big.NewRat(1, 6)

  sum := new(big.Rat).Add(r1, r2)
  diff := new(big.Rat).Sub(r1, r2)
  prod := new(big.Rat).Mul(r1, r2)
  quot := new(big.Rat).Quo(r1, r2)

  fmt.Println("Sum:", sum)
  fmt.Println("Difference:", diff)
  fmt.Println("Product:", prod)
  fmt.Println("Quotient:", quot)
}

Результат выполнения кода:

go"Sum: 1/2"
"Difference: 1/6"
"Product: 1/18"
"Quotient: 2/1"

Сравнение чисел

Для сравнения двух рациональных чисел используется метод Cmp. Он возвращает -1, если число меньше аргумента; 0, если они равны; и 1, если число больше аргумента.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r1 := big.NewRat(2, 5)
  r2 := big.NewRat(3, 7)

  cmp := r1.Cmp(r2)
  if cmp < 0 {
    fmt.Println("r1 < r2")
  } else if cmp == 0 {
    fmt.Println("r1 == r2")
  } else {
    fmt.Println("r1 > r2")
  }
}

Результат выполнения кода:

go"r1 < r2"

Преобразование в другие типы

Метод FloatString преобразует рациональное число в строку с плавающей точкой с указанным количеством знаков после запятой.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := big.NewRat(22, 7)
  fmt.Println(r.FloatString(5))
}

Результат выполнения кода:

go"3.14286"

Метод Float64 возвращает приближенное значение типа float64. Второе возвращаемое значение указывает, является ли преобразование точным.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := big.NewRat(1, 3)
  val, exact := r.Float64()
  fmt.Printf("Value: %f, Exact: %t\n", val, exact)
}

Результат выполнения кода:

go"Value: 0.333333, Exact: false"

Получение числителя и знаменателя

Методы Num и Denom возвращают числитель и знаменатель рационального числа в виде указателей на big.Int.

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r := big.NewRat(15, 20)
  num := r.Num()
  den := r.Denom()
  fmt.Println("Numerator:", num)
  fmt.Println("Denominator:", den)
}

Результат выполнения кода:

go"Numerator: 15"
"Denominator: 20"

Обратите внимание, что методы Num и Denom возвращают некопированные внутренние значения. Изменение их влияет на исходное рациональное число, поэтому будьте осторожны при их использовании.

Пример практического применения

Рассмотрим пример вычисления суммы дробей с последующим сокращением результата:

gopackage main

import (
  "fmt"
  "math/big"
)

func main() {
  r1 := big.NewRat(2, 3)
  r2 := big.NewRat(3, 4)
  r3 := big.NewRat(5, 6)

  sum := new(big.Rat).Add(r1, r2)
  sum.Add(sum, r3)

  fmt.Println("Sum:", sum)
  fmt.Println("Float:", sum.FloatString(3))
}

Результат выполнения кода:

go"Sum: 9/4"
"Float: 2.250"

Смотрите также

  • тип big.Float,
    который представляет числа с плавающей точкой произвольной точности
  • тип big.Int,
    который представляет целые числа произвольной точности
  • функцию big.NewRat,
    которая создает новое рациональное число из числителя и знаменателя
  • метод big.Rat.SetFrac,
    который устанавливает значение рационального числа из двух целых чисел