// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package testlapack import ( "fmt" "math" "testing" ) type Dlartger interface { Dlartg(f, g float64) (cs, sn, r float64) } func DlartgTest(t *testing.T, impl Dlartger) { const tol = 20 * ulp values := []float64{ -safmax, -1 / ulp, -1, -1.0 / 3, -ulp, -safmin, 0, safmin, ulp, 1.0 / 3, 1, 1 / ulp, safmax, math.Inf(-1), math.Inf(1), math.NaN(), } for _, f := range values { for _, g := range values { name := fmt.Sprintf("Case f=%v,g=%v", f, g) // Generate a plane rotation so that // [ cs sn] * [f] = [r] // [-sn cs] [g] = [0] // where cs*cs + sn*sn = 1. cs, sn, r := impl.Dlartg(f, g) switch { case math.IsNaN(f) || math.IsNaN(g): if !math.IsNaN(r) { t.Errorf("%v: unexpected r=%v; want NaN", name, r) } case math.IsInf(f, 0) || math.IsInf(g, 0): if !math.IsNaN(r) && !math.IsInf(r, 0) { t.Errorf("%v: unexpected r=%v; want NaN or Inf", name, r) } default: d := math.Max(math.Abs(f), math.Abs(g)) d = math.Min(math.Max(safmin, d), safmax) fs := f / d gs := g / d rs := r / d // Check that cs*f + sn*g = r. rnorm := math.Abs(rs) if rnorm == 0 { rnorm = math.Max(math.Abs(fs), math.Abs(gs)) if rnorm == 0 { rnorm = 1 } } resid := math.Abs(rs-(cs*fs+sn*gs)) / rnorm if resid > tol { t.Errorf("%v: cs*f + sn*g != r; resid=%v", name, resid) } // Check that -sn*f + cs*g = 0. resid = math.Abs(-sn*fs + cs*gs) if resid > tol { t.Errorf("%v: -sn*f + cs*g != 0; resid=%v", name, resid) } // Check that cs*cs + sn*sn = 1. resid = math.Abs(1 - (cs*cs + sn*sn)) if resid > tol { t.Errorf("%v: cs*cs + sn*sn != 1; resid=%v", name, resid) } // Check that cs is non-negative. if math.Abs(f) > math.Abs(g) && cs < 0 { t.Errorf("%v: cs is negative; cs=%v", name, cs) } } } } }