mirror of
https://github.com/gonum/gonum.git
synced 2025-11-01 02:52:49 +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
|
CMOVQLE t_len+32(FP), DX
|
||||||
PXOR X3, X3
|
PXOR X3, X3
|
||||||
XORQ AX, AX
|
XORQ AX, AX
|
||||||
CMPQ DX, $0
|
|
||||||
JE l1_end
|
|
||||||
CMPQ DX, $1
|
CMPQ DX, $1
|
||||||
JL l1_tail
|
JL l1_end
|
||||||
|
SUBQ $1, DX
|
||||||
|
JE l1_tail
|
||||||
l1_loop:
|
l1_loop:
|
||||||
MOVUPS (SI)(AX*8), X0
|
MOVUPS (SI)(AX*8), X0
|
||||||
MOVUPS (DI)(AX*8), X1
|
MOVUPS (DI)(AX*8), X1
|
||||||
MOVAPS X0,X2
|
MOVAPS X0, X2
|
||||||
SUBPD X1, X0
|
SUBPD X1, X0
|
||||||
SUBPD X2, X1
|
SUBPD X2, X1
|
||||||
MAXPD X1, X0
|
MAXPD X1, X0
|
||||||
@@ -28,20 +28,20 @@ l1_loop:
|
|||||||
ADDQ $2, AX
|
ADDQ $2, AX
|
||||||
CMPQ AX, DX
|
CMPQ AX, DX
|
||||||
JL l1_loop
|
JL l1_loop
|
||||||
JE l1_end
|
JG l1_end
|
||||||
l1_tail:
|
l1_tail:
|
||||||
PXOR X0 ,X0
|
PXOR X0 ,X0
|
||||||
PXOR X1 ,X1
|
PXOR X1 ,X1
|
||||||
MOVSD (SI)(AX*8), X0
|
MOVSD (SI)(AX*8), X0
|
||||||
MOVSD (DI)(AX*8), X1
|
MOVSD (DI)(AX*8), X1
|
||||||
MOVUPS X0, X2
|
MOVAPD X0, X2
|
||||||
SUBPD X1, X0
|
SUBSD X1, X0
|
||||||
SUBPD X2, X1
|
SUBSD X2, X1
|
||||||
MAXPD X1, X0
|
MAXSD X1, X0
|
||||||
ADDPD X0, X3
|
ADDSD X0, X3
|
||||||
l1_end:
|
l1_end:
|
||||||
MOVAPS X3, X2
|
MOVAPS X3, X2
|
||||||
SHUFPD $1, X3, X2
|
SHUFPD $1, X2, X2
|
||||||
ADDSD X3, X2
|
ADDSD X3, X2
|
||||||
MOVSD X2, ret+48(FP)
|
MOVSD X2, ret+48(FP)
|
||||||
RET
|
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 L1norm(s, t []float64) float64
|
||||||
|
|
||||||
|
func LinfNorm(s, t []float64) float64
|
||||||
|
|
||||||
func ScalUnitary(alpha float64, x []float64)
|
func ScalUnitary(alpha float64, x []float64)
|
||||||
|
|
||||||
func ScalUnitaryTo(dst []float64, alpha float64, x []float64)
|
func ScalUnitaryTo(dst []float64, alpha float64, x []float64)
|
||||||
|
|||||||
@@ -6,15 +6,22 @@ package f64
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var nan, inf, ninf float64
|
var (
|
||||||
|
nan, inf, ninf float64
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
nan, inf, ninf = math.NaN(), math.Inf(1), math.Inf(-1)
|
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) {
|
func TestAdd(t *testing.T) {
|
||||||
for j, v := range []struct {
|
for j, v := range []struct {
|
||||||
dst, src, expect []float64
|
dst, src, expect []float64
|
||||||
@@ -32,13 +39,14 @@ func TestAdd(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
Add(v.dst, v.src)
|
Add(v.dst, v.src)
|
||||||
for i := range v.expect {
|
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.Log("Test", j, "Add error at", i, "Got:", v.dst[i], "Expected:", v.expect[i])
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
runtime.GC()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddConst(t *testing.T) {
|
func TestAddConst(t *testing.T) {
|
||||||
@@ -54,12 +62,13 @@ func TestAddConst(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
AddConst(v.alpha, v.src)
|
AddConst(v.alpha, v.src)
|
||||||
for i := range v.expect {
|
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.Log("Test", j, "AddConst error at", i, "Got:", v.src[i], "Expected:", v.expect[i])
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
runtime.GC()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCumSum(t *testing.T) {
|
func TestCumSum(t *testing.T) {
|
||||||
@@ -80,26 +89,26 @@ func TestCumSum(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
ret := CumSum(v.dst, v.src)
|
ret := CumSum(v.dst, v.src)
|
||||||
for i := range v.expect {
|
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.Log("Test", j, "CumSum error at", i, "Got:", ret[i], "Expected:", v.expect[i])
|
||||||
t.Fail()
|
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.Log("Test", j, "CumSum ret/dst mismatch", i, "Ret:", ret[i], "Dst:", v.dst[i])
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
runtime.GC()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCumProd(t *testing.T) {
|
func TestCumProd(t *testing.T) {
|
||||||
nan, inf, ninf := math.NaN(), math.Inf(1), math.Inf(-1)
|
|
||||||
for j, v := range []struct {
|
for j, v := range []struct {
|
||||||
dst, src, expect []float64
|
dst, src, expect []float64
|
||||||
}{
|
}{
|
||||||
{[]float64{1}, []float64{1}, []float64{1}},
|
{[]float64{1}, []float64{1}, []float64{1}},
|
||||||
{[]float64{nan}, []float64{nan}, []float64{nan}},
|
{[]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}, []float64{1, 2, 3, 4}, []float64{1, 2, 6}},
|
||||||
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, []float64{1, 2, 6}},
|
{[]float64{0, 0, 0, 0}, []float64{1, 2, 3}, []float64{1, 2, 6}},
|
||||||
{[]float64{nan, 1, nan, 1, 0},
|
{[]float64{nan, 1, nan, 1, 0},
|
||||||
@@ -111,16 +120,118 @@ func TestCumProd(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
ret := CumProd(v.dst, v.src)
|
ret := CumProd(v.dst, v.src)
|
||||||
for i := range v.expect {
|
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.Log("Test", j, "CumProd error at", i, "Got:", ret[i], "Expected:", v.expect[i])
|
||||||
t.Fail()
|
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.Log("Test", j, "CumProd ret/dst mismatch", i, "Ret:", ret[i], "Dst:", v.dst[i])
|
||||||
t.Fail()
|
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