| // $G $D/$F.go && $L $F.$A && ./$A.out |
| |
| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // A little test program for rational arithmetics. |
| // Computes a Hilbert matrix, its inverse, multiplies them |
| // and verifies that the product is the identity matrix. |
| |
| package main |
| |
| import Big "bignum" |
| import Fmt "fmt" |
| |
| |
| func assert(p bool) { |
| if !p { |
| panic("assert failed"); |
| } |
| } |
| |
| |
| var ( |
| Zero = Big.Rat(0, 1); |
| One = Big.Rat(1, 1); |
| ) |
| |
| |
| type Matrix struct { |
| n, m int; |
| a []*Big.Rational; |
| } |
| |
| |
| func (a *Matrix) at(i, j int) *Big.Rational { |
| assert(0 <= i && i < a.n && 0 <= j && j < a.m); |
| return a.a[i*a.m + j]; |
| } |
| |
| |
| func (a *Matrix) set(i, j int, x *Big.Rational) { |
| assert(0 <= i && i < a.n && 0 <= j && j < a.m); |
| a.a[i*a.m + j] = x; |
| } |
| |
| |
| func NewMatrix(n, m int) *Matrix { |
| assert(0 <= n && 0 <= m); |
| a := new(Matrix); |
| a.n = n; |
| a.m = m; |
| a.a = make([]*Big.Rational, n*m); |
| return a; |
| } |
| |
| |
| func NewUnit(n int) *Matrix { |
| a := NewMatrix(n, n); |
| for i := 0; i < n; i++ { |
| for j := 0; j < n; j++ { |
| x := Zero; |
| if i == j { |
| x = One; |
| } |
| a.set(i, j, x); |
| } |
| } |
| return a; |
| } |
| |
| |
| func NewHilbert(n int) *Matrix { |
| a := NewMatrix(n, n); |
| for i := 0; i < n; i++ { |
| for j := 0; j < n; j++ { |
| x := Big.Rat(1, i + j + 1); |
| a.set(i, j, x); |
| } |
| } |
| return a; |
| } |
| |
| |
| func MakeRat(x Big.Natural) *Big.Rational { |
| return Big.MakeRat(Big.MakeInt(false, x), Big.Nat(1)); |
| } |
| |
| |
| func NewInverseHilbert(n int) *Matrix { |
| a := NewMatrix(n, n); |
| for i := 0; i < n; i++ { |
| for j := 0; j < n; j++ { |
| x0 := One; |
| if (i+j)&1 != 0 { |
| x0 = x0.Neg(); |
| } |
| x1 := Big.Rat(i + j + 1, 1); |
| x2 := MakeRat(Big.Binomial(uint(n+i), uint(n-j-1))); |
| x3 := MakeRat(Big.Binomial(uint(n+j), uint(n-i-1))); |
| x4 := MakeRat(Big.Binomial(uint(i+j), uint(i))); |
| x4 = x4.Mul(x4); |
| a.set(i, j, x0.Mul(x1).Mul(x2).Mul(x3).Mul(x4)); |
| } |
| } |
| return a; |
| } |
| |
| |
| func (a *Matrix) Mul(b *Matrix) *Matrix { |
| assert(a.m == b.n); |
| c := NewMatrix(a.n, b.m); |
| for i := 0; i < c.n; i++ { |
| for j := 0; j < c.m; j++ { |
| x := Zero; |
| for k := 0; k < a.m; k++ { |
| x = x.Add(a.at(i, k).Mul(b.at(k, j))); |
| } |
| c.set(i, j, x); |
| } |
| } |
| return c; |
| } |
| |
| |
| func (a *Matrix) Eql(b *Matrix) bool { |
| if a.n != b.n || a.m != b.m { |
| return false; |
| } |
| for i := 0; i < a.n; i++ { |
| for j := 0; j < a.m; j++ { |
| if a.at(i, j).Cmp(b.at(i,j)) != 0 { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| |
| func (a *Matrix) String() string { |
| s := ""; |
| for i := 0; i < a.n; i++ { |
| for j := 0; j < a.m; j++ { |
| s += Fmt.Sprintf("\t%s", a.at(i, j)); |
| } |
| s += "\n"; |
| } |
| return s; |
| } |
| |
| |
| func main() { |
| n := 10; |
| a := NewHilbert(n); |
| b := NewInverseHilbert(n); |
| I := NewUnit(n); |
| ab := a.Mul(b); |
| if !ab.Eql(I) { |
| Fmt.Println("a =", a); |
| Fmt.Println("b =", b); |
| Fmt.Println("a*b =", ab); |
| Fmt.Println("I =", I); |
| panic("FAILED"); |
| } |
| } |