mirror of
https://github.com/gonum/gonum.git
synced 2025-10-20 21:59:25 +08:00
Add drscl and tests, and fix the dlamch parameters while here.
This commit is contained in:
41
native/drscl.go
Normal file
41
native/drscl.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/blas/blas64"
|
||||
)
|
||||
|
||||
// Drscl multiplies the vector x by 1/a being careful to avoid overflow or
|
||||
// underflow where possible.
|
||||
func (impl Implementation) Drscl(n int, a float64, x []float64, incX int) {
|
||||
checkVector(n, x, incX)
|
||||
bi := blas64.Implementation()
|
||||
cden := a
|
||||
cnum := 1.0
|
||||
smlnum := dlamchS
|
||||
bignum := 1 / smlnum
|
||||
for {
|
||||
cden1 := cden * smlnum
|
||||
cnum1 := cnum / bignum
|
||||
var mul float64
|
||||
var done bool
|
||||
switch {
|
||||
case cnum != 0 && math.Abs(cden1) > math.Abs(cnum):
|
||||
mul = smlnum
|
||||
done = false
|
||||
cden = cden1
|
||||
case math.Abs(cnum1) > math.Abs(cden):
|
||||
mul = bignum
|
||||
done = false
|
||||
cnum = cnum1
|
||||
default:
|
||||
mul = cnum / cden
|
||||
done = true
|
||||
}
|
||||
bi.Dscal(n, mul, x, incX)
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@@ -78,18 +78,15 @@ func max(a, b int) int {
|
||||
// fixed values. Probably a way to get them as constants.
|
||||
// TODO(btracey): Is there a better way to find the smallest number such that 1+E > 1
|
||||
|
||||
var dlamchE, dlamchS, dlamchP float64
|
||||
var (
|
||||
// dlamchE is the machine epsilon. For IEEE this is 2^-53.
|
||||
dlamchE = math.Float64frombits(0x3ca0000000000000)
|
||||
|
||||
func init() {
|
||||
onePlusEps := math.Nextafter(1, math.Inf(1))
|
||||
eps := (math.Nextafter(1, math.Inf(1)) - 1) * 0.5
|
||||
dlamchE = eps
|
||||
sfmin := math.SmallestNonzeroFloat64
|
||||
small := 1 / math.MaxFloat64
|
||||
if small >= sfmin {
|
||||
sfmin = small * onePlusEps
|
||||
}
|
||||
dlamchS = sfmin
|
||||
radix := 2.0
|
||||
dlamchP = radix * eps
|
||||
}
|
||||
// dlamchP is 2 * eps
|
||||
dlamchP = math.Float64frombits(0x3cb0000000000000)
|
||||
|
||||
// dlamchS is the "safe min", that is, the lowest number such that 1/sfmin does
|
||||
// not overflow. The Netlib code for calculating this number is not correct --
|
||||
// it overflows. Found by trial and error, it is equal to (1/math.MaxFloat64) * (1+ 6*eps)
|
||||
dlamchS = math.Float64frombits(0x4000000000001)
|
||||
)
|
||||
|
@@ -88,6 +88,10 @@ func TestDpotrf(t *testing.T) {
|
||||
testlapack.DpotrfTest(t, impl)
|
||||
}
|
||||
|
||||
func TestDrscl(t *testing.T) {
|
||||
testlapack.DrsclTest(t, impl)
|
||||
}
|
||||
|
||||
func TestIladlc(t *testing.T) {
|
||||
testlapack.IladlcTest(t, impl)
|
||||
}
|
||||
|
48
testlapack/drscl.go
Normal file
48
testlapack/drscl.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package testlapack
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/gonum/floats"
|
||||
)
|
||||
|
||||
type Drscler interface {
|
||||
Drscl(n int, a float64, x []float64, incX int)
|
||||
}
|
||||
|
||||
func DrsclTest(t *testing.T, impl Drscler) {
|
||||
for _, test := range []struct {
|
||||
x []float64
|
||||
a float64
|
||||
}{
|
||||
{
|
||||
x: []float64{1, 2, 3, 4, 5},
|
||||
a: 4,
|
||||
},
|
||||
{
|
||||
x: []float64{1, 2, 3, 4, 5},
|
||||
a: math.MaxFloat64,
|
||||
},
|
||||
{
|
||||
x: []float64{1, 2, 3, 4, 5},
|
||||
a: 1e-307,
|
||||
},
|
||||
} {
|
||||
xcopy := make([]float64, len(test.x))
|
||||
copy(xcopy, test.x)
|
||||
|
||||
// Cannot test the scaling directly because of floating point scaling issues
|
||||
// (the purpose of Drscl). Instead, check that scaling and scaling back
|
||||
// yeilds approximately x. If overflow or underflow occurs then the scaling
|
||||
// won't match.
|
||||
impl.Drscl(len(test.x), test.a, xcopy, 1)
|
||||
if floats.Equal(xcopy, test.x) {
|
||||
t.Errorf("x unchanged during call to drscl. a = %v, x = %v.", test.a, test.x)
|
||||
}
|
||||
impl.Drscl(len(test.x), 1/test.a, xcopy, 1)
|
||||
if !floats.EqualApprox(xcopy, test.x, 1e-14) {
|
||||
t.Errorf("x not equal after scaling and unscaling. a = %v, x = %v.", test.a, test.x)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user