mirror of
https://github.com/gonum/gonum.git
synced 2025-10-31 02:26:59 +08:00
f64 lnorm implementations for L=1 (L1norm) and L=inf (LinfNorm) with tests
This commit is contained in:
@@ -13,14 +13,14 @@ TEXT ·L1norm(SB), NOSPLIT, $0
|
||||
CMOVQLE t_len+32(FP), DX
|
||||
PXOR X3, X3
|
||||
XORQ AX, AX
|
||||
CMPQ DX, $0
|
||||
JE l1_end
|
||||
CMPQ DX, $1
|
||||
JL l1_tail
|
||||
JL l1_end
|
||||
SUBQ $1, DX
|
||||
JE l1_tail
|
||||
l1_loop:
|
||||
MOVUPS (SI)(AX*8), X0
|
||||
MOVUPS (DI)(AX*8), X1
|
||||
MOVAPS X0,X2
|
||||
MOVAPS X0, X2
|
||||
SUBPD X1, X0
|
||||
SUBPD X2, X1
|
||||
MAXPD X1, X0
|
||||
@@ -28,20 +28,20 @@ l1_loop:
|
||||
ADDQ $2, AX
|
||||
CMPQ AX, DX
|
||||
JL l1_loop
|
||||
JE l1_end
|
||||
JG l1_end
|
||||
l1_tail:
|
||||
PXOR X0 ,X0
|
||||
PXOR X1 ,X1
|
||||
MOVSD (SI)(AX*8), X0
|
||||
MOVSD (DI)(AX*8), X1
|
||||
MOVUPS X0, X2
|
||||
SUBPD X1, X0
|
||||
SUBPD X2, X1
|
||||
MAXPD X1, X0
|
||||
ADDPD X0, X3
|
||||
MOVAPD X0, X2
|
||||
SUBSD X1, X0
|
||||
SUBSD X2, X1
|
||||
MAXSD X1, X0
|
||||
ADDSD X0, X3
|
||||
l1_end:
|
||||
MOVAPS X3, X2
|
||||
SHUFPD $1, X3, X2
|
||||
SHUFPD $1, X2, X2
|
||||
ADDSD X3, X2
|
||||
MOVSD X2, ret+48(FP)
|
||||
RET
|
||||
|
||||
47
asm/f64/linfnorm_amd.s
Normal file
47
asm/f64/linfnorm_amd.s
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright ©2016 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.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//func LinfNorm(s, t []float64) float64
|
||||
TEXT ·LinfNorm(SB), NOSPLIT, $0
|
||||
MOVQ s_base+0(FP), DI
|
||||
MOVQ t_base+24(FP), SI
|
||||
MOVQ s_len+8(FP), DX
|
||||
CMPQ t_len+32(FP), DX
|
||||
CMOVQLE t_len+32(FP), DX
|
||||
PXOR X3, X3
|
||||
XORQ AX, AX
|
||||
CMPQ DX, $1
|
||||
JL l1_end
|
||||
SUBQ $1, DX
|
||||
JE l1_tail
|
||||
l1_loop:
|
||||
MOVUPS (SI)(AX*8), X0
|
||||
MOVUPS (DI)(AX*8), X1
|
||||
MOVAPS X0, X2
|
||||
SUBPD X1, X0
|
||||
SUBPD X2, X1
|
||||
MAXPD X1, X0
|
||||
MAXPD X0, X3
|
||||
ADDQ $2, AX
|
||||
CMPQ AX, DX
|
||||
JL l1_loop
|
||||
JG l1_end
|
||||
l1_tail:
|
||||
PXOR X0 ,X0
|
||||
PXOR X1 ,X1
|
||||
MOVSD (SI)(AX*8), X0
|
||||
MOVSD (DI)(AX*8), X1
|
||||
MOVAPD X0, X2
|
||||
SUBSD X1, X0
|
||||
SUBSD X2, X1
|
||||
MAXSD X1, X0
|
||||
MAXSD X0, X3
|
||||
l1_end:
|
||||
MOVAPS X3, X2
|
||||
SHUFPD $1, X2, X2
|
||||
MAXSD X3, X2
|
||||
MOVSD X2, ret+48(FP)
|
||||
RET
|
||||
@@ -32,6 +32,8 @@ func DotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64)
|
||||
|
||||
func L1norm(s, t []float64) float64
|
||||
|
||||
func LinfNorm(s, t []float64) float64
|
||||
|
||||
func ScalUnitary(alpha float64, x []float64)
|
||||
|
||||
func ScalUnitaryTo(dst []float64, alpha float64, x []float64)
|
||||
|
||||
@@ -6,15 +6,22 @@ package f64
|
||||
|
||||
import (
|
||||
"math"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var nan, inf, ninf float64
|
||||
var (
|
||||
nan, inf, ninf float64
|
||||
)
|
||||
|
||||
func init() {
|
||||
nan, inf, ninf = math.NaN(), math.Inf(1), math.Inf(-1)
|
||||
}
|
||||
|
||||
func diff(a, b float64) bool {
|
||||
return a != b && !math.IsNaN(a) && !math.IsNaN(b) || (math.IsNaN(a) != math.IsNaN(b))
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
for j, v := range []struct {
|
||||
dst, src, expect []float64
|
||||
@@ -32,13 +39,14 @@ func TestAdd(t *testing.T) {
|
||||
} {
|
||||
Add(v.dst, v.src)
|
||||
for i := range v.expect {
|
||||
if v.dst[i] != v.expect[i] && (math.IsNaN(v.dst[i]) != math.IsNaN(v.expect[i])) {
|
||||
if diff(v.dst[i], v.expect[i]) {
|
||||
|
||||
t.Log("Test", j, "Add error at", i, "Got:", v.dst[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestAddConst(t *testing.T) {
|
||||
@@ -54,12 +62,13 @@ func TestAddConst(t *testing.T) {
|
||||
} {
|
||||
AddConst(v.alpha, v.src)
|
||||
for i := range v.expect {
|
||||
if v.src[i] != v.expect[i] && (math.IsNaN(v.src[i]) != math.IsNaN(v.expect[i])) {
|
||||
if diff(v.src[i], v.expect[i]) {
|
||||
t.Log("Test", j, "AddConst error at", i, "Got:", v.src[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestCumSum(t *testing.T) {
|
||||
@@ -80,26 +89,26 @@ func TestCumSum(t *testing.T) {
|
||||
} {
|
||||
ret := CumSum(v.dst, v.src)
|
||||
for i := range v.expect {
|
||||
if ret[i] != v.expect[i] && (math.IsNaN(ret[i]) != math.IsNaN(v.expect[i])) {
|
||||
if diff(ret[i], v.expect[i]) {
|
||||
t.Log("Test", j, "CumSum error at", i, "Got:", ret[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
if ret[i] != v.dst[i] && (math.IsNaN(ret[i]) != math.IsNaN(v.dst[i])) {
|
||||
if diff(ret[i], v.dst[i]) {
|
||||
t.Log("Test", j, "CumSum ret/dst mismatch", i, "Ret:", ret[i], "Dst:", v.dst[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestCumProd(t *testing.T) {
|
||||
nan, inf, ninf := math.NaN(), math.Inf(1), math.Inf(-1)
|
||||
for j, v := range []struct {
|
||||
dst, src, expect []float64
|
||||
}{
|
||||
{[]float64{1}, []float64{1}, []float64{1}},
|
||||
{[]float64{nan}, []float64{nan}, []float64{nan}},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3, 4}, []float64{1, 2, 6, 12}},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3, 4}, []float64{1, 2, 6, 24}},
|
||||
{[]float64{0, 0, 0}, []float64{1, 2, 3, 4}, []float64{1, 2, 6}},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, []float64{1, 2, 6}},
|
||||
{[]float64{nan, 1, nan, 1, 0},
|
||||
@@ -111,16 +120,118 @@ func TestCumProd(t *testing.T) {
|
||||
} {
|
||||
ret := CumProd(v.dst, v.src)
|
||||
for i := range v.expect {
|
||||
if ret[i] != v.expect[i] && (math.IsNaN(ret[i]) != math.IsNaN(v.expect[i])) {
|
||||
if diff(ret[i], v.expect[i]) {
|
||||
t.Log("Test", j, "CumProd error at", i, "Got:", ret[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
if ret[i] != v.dst[i] && (math.IsNaN(ret[i]) != math.IsNaN(v.dst[i])) {
|
||||
if diff(ret[i], v.dst[i]) {
|
||||
t.Log("Test", j, "CumProd ret/dst mismatch", i, "Ret:", ret[i], "Dst:", v.dst[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
//func TestDiv
|
||||
func TestDiv(t *testing.T) {
|
||||
for j, v := range []struct {
|
||||
dst, src, expect []float64
|
||||
}{
|
||||
{[]float64{1}, []float64{1}, []float64{1}},
|
||||
{[]float64{nan}, []float64{nan}, []float64{nan}},
|
||||
{[]float64{1, 2, 3, 4}, []float64{1, 2, 3, 4}, []float64{1, 1, 1, 1}},
|
||||
{[]float64{2, 4, 6}, []float64{1, 2, 3, 4}, []float64{2, 2, 2}},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, []float64{0, 0, 0}},
|
||||
{[]float64{nan, 1, nan, 1, 0},
|
||||
[]float64{1, 1, nan, 1, 1},
|
||||
[]float64{nan, 1, nan, 1, 0}},
|
||||
{[]float64{inf, 4, nan, ninf, 9},
|
||||
[]float64{inf, 4, nan, ninf, 3},
|
||||
[]float64{nan, 1, nan, nan, 3}},
|
||||
} {
|
||||
Div(v.dst, v.src)
|
||||
for i := range v.expect {
|
||||
if diff(v.dst[i], v.expect[i]) {
|
||||
t.Log("Test", j, "Div error at", i, "Got:", v.dst[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestDivTo(t *testing.T) {
|
||||
for j, v := range []struct {
|
||||
dst, src, expect []float64
|
||||
}{
|
||||
{[]float64{1}, []float64{1}, []float64{1}},
|
||||
{[]float64{nan}, []float64{nan}, []float64{nan}},
|
||||
{[]float64{1, 2, 3, 4}, []float64{1, 2, 3, 4}, []float64{1, 1, 1, 1}},
|
||||
{[]float64{2, 4, 6}, []float64{1, 2, 3, 4}, []float64{2, 2, 2}},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, []float64{0, 0, 0}},
|
||||
{[]float64{nan, 1, nan, 1, 0},
|
||||
[]float64{1, 1, nan, 1, 1},
|
||||
[]float64{nan, 1, nan, 1, 0}},
|
||||
{[]float64{inf, 4, nan, ninf, 9},
|
||||
[]float64{inf, 4, nan, ninf, 3},
|
||||
[]float64{nan, 1, nan, nan, 3}},
|
||||
} {
|
||||
ret := DivTo(v.dst, v.dst, v.src)
|
||||
for i := range v.expect {
|
||||
if diff(ret[i], v.expect[i]) {
|
||||
t.Log("Test", j, "DivTo error at", i, "Got:", v.dst[i], "Expected:", v.expect[i])
|
||||
t.Fail()
|
||||
}
|
||||
if diff(ret[i], v.dst[i]) {
|
||||
t.Log("Test", j, "DivTo ret/dst mismatch", i, "Ret:", ret[i], "Dst:", v.dst[i])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestL1norm(t *testing.T) {
|
||||
for j, v := range []struct {
|
||||
s, t []float64
|
||||
expect float64
|
||||
}{
|
||||
{[]float64{1}, []float64{1}, 0},
|
||||
{[]float64{nan}, []float64{nan}, nan},
|
||||
{[]float64{1, 2, 3, 4}, []float64{1, 2, 3, 4}, 0},
|
||||
{[]float64{2, 4, 6}, []float64{1, 2, 3, 4}, 6},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, 6},
|
||||
{[]float64{0, -4, -10, 0}, []float64{1, 2, 3}, 20},
|
||||
{[]float64{0, 1, 0, 1, 0}, []float64{1, 1, inf, 1, 1}, inf},
|
||||
{[]float64{inf, 4, nan, ninf, 9}, []float64{inf, 4, nan, ninf, 3}, nan},
|
||||
} {
|
||||
ret := L1norm(v.s, v.t)
|
||||
if diff(ret, v.expect) {
|
||||
t.Log("Test", j, "L1norm error. Got:", ret, "Expected:", v.expect)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func TestLinfNorm(t *testing.T) {
|
||||
for j, v := range []struct {
|
||||
s, t []float64
|
||||
expect float64
|
||||
}{
|
||||
{[]float64{1}, []float64{1}, 0},
|
||||
{[]float64{nan}, []float64{nan}, nan},
|
||||
{[]float64{1, 2, 3, 4}, []float64{1, 2, 3, 4}, 0},
|
||||
{[]float64{2, 4, 6}, []float64{1, 2, 3, 4}, 3},
|
||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, 3},
|
||||
{[]float64{0, 1, 0, 1, 0}, []float64{1, 1, inf, 1, 1}, inf},
|
||||
{[]float64{inf, 4, nan, ninf, 9}, []float64{inf, 4, nan, ninf, 3}, 6},
|
||||
} {
|
||||
ret := LinfNorm(v.s, v.t)
|
||||
if diff(ret, v.expect) {
|
||||
t.Log("Test", j, "LinfNorm error. Got:", ret, "Expected:", v.expect)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user