diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..da13d98f358bb2c563548e899e4b260561cd5327 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.DS_Store +.idea/ +target/ +*.iml +assembly/version.env +assembly/version.properties + +# VS CODE +.vscode/ +.classpath +.factorypath +.project +.settings/ + +# go.test.sh +coverage.txt + +# test +tutorials.csv diff --git a/algorithms/aggregates.go b/algorithms/aggregates.go deleted file mode 100644 index cad707a67ffef85476683e04fe8f149f33a097e9..0000000000000000000000000000000000000000 --- a/algorithms/aggregates.go +++ /dev/null @@ -1,77 +0,0 @@ -package algorithms - -type Number interface { - ~int64 | float64 -} - -func Sum_Go[T Number](x []T) T { - sum := T(0) - for i := 0; i < len(x); i++ { - sum += x[i] - } - return sum -} - -func CumSum_Go[T Number](x []T) { - sum := T(0) - for i := 0; i < len(x); i++ { - sum += x[i] - x[i] = sum - } -} - -func Prod_Go[T Number](x []T) T { - prod := T(1) - for i := 0; i < len(x); i++ { - prod *= x[i] - } - return prod -} - -func CumProd_Go[T Number](x []T) { - prod := T(1) - for i := 0; i < len(x); i++ { - prod *= x[i] - x[i] = prod - } -} - -func Mean_Go[T Number](x []T) T { - return Sum_Go(x) / T(len(x)) -} - -//func Median_Go[T Number](x []T) T { -// if len(x)%2 == 1 { -// x = slices.Clone(x) -// i := len(x) / 2 -// partial.TopK(x, i+1) -// return x[i] -// } -// return Quantile_Go(x, T(0.5)) -//} -// -//func Quantile_Go[T Number](x []T, q T) T { -// if len(x) == 1 { -// return x[0] -// } -// if q == T(0) { -// return Min_Go(x) -// } -// if q == T(1) { -// return Max_Go(x) -// } -// x = slices.Clone(x) -// f := T(len(x)-1) * q -// i := int(math.Floor(float64(f))) -// if q < 0.5 { -// partial.TopK(x, i+2) -// a := Max_Go(x[:i+1]) -// b := x[i+1] -// return a + (b-a)*(f-T(i)) -// } else { -// partial.TopK(x, i+1) -// a := x[i] -// b := Min_Go(x[i+1:]) -// return a + (b-a)*(f-T(i)) -// } -//} diff --git a/algorithms/avx2/vek_float64.go b/algorithms/avx2/vek.go similarity index 88% rename from algorithms/avx2/vek_float64.go rename to algorithms/avx2/vek.go index 53fbddeb08561dda95aa88646705b848b5343294..45823754d8a504e3e82e1656d325287c9deeee78 100644 --- a/algorithms/avx2/vek_float64.go +++ b/algorithms/avx2/vek.go @@ -3,6 +3,7 @@ package avx2 import "github.com/viterin/vek" // 初始化 avx2 +// 可以参考另一个实现库 gonum.org/v1/gonum/stat func init() { // 开启加速选项 vek.SetAcceleration(true) @@ -27,9 +28,10 @@ func Round(x []float64) { vek.Round_Inplace(x) } func Ceil(x []float64) { vek.Ceil_Inplace(x) } func Floor(x []float64) { vek.Floor_Inplace(x) } -func Min(x []float64) float64 { return vek.Min(x) } -func Max(x []float64) float64 { return vek.Max(x) } -func Mean(x []float64) float64 { return vek.Mean(x) } +func Min(x []float64) float64 { return vek.Min(x) } +func Max(x []float64) float64 { return vek.Max(x) } +func Mean(x []float64) float64 { return vek.Mean(x) } +func Median(x []float64) float64 { return vek.Median(x) } func Dot(x []float64, y []float64) float64 { return vek.Dot(x, y) } diff --git a/algorithms/avx2/vek_float64_test.go b/algorithms/avx2/vek_test.go similarity index 100% rename from algorithms/avx2/vek_float64_test.go rename to algorithms/avx2/vek_test.go diff --git a/algorithms/float64.go b/algorithms/float64.go deleted file mode 100644 index 465d7cbd7b82fe22229b1069d93c664af9a1d46e..0000000000000000000000000000000000000000 --- a/algorithms/float64.go +++ /dev/null @@ -1,543 +0,0 @@ -package algorithms - -import ( - m "math" -) - -// Round returns the nearest integer, rounding half away from zero. -// -// Special cases are: -// -// Round(±0) = ±0 -// Round(±Inf) = ±Inf -// Round(NaN) = NaN -func Round(x float64) float64 { return m.Round(x) } - -// RoundToEven returns the nearest integer, rounding ties to even. -// -// Special cases are: -// -// RoundToEven(±0) = ±0 -// RoundToEven(±Inf) = ±Inf -// RoundToEven(NaN) = NaN -func RoundToEven(x float64) float64 { return m.RoundToEven(x) } - -// NaN returns an IEEE 754 “not-a-number” value. -func NaN() float64 { return m.NaN() } - -// IsNaN reports whether f is an IEEE 754 “not-a-number” value. -func IsNaN(x float64) bool { return m.IsNaN(x) } - -// IsInf reports whether f is an infinity, according to sign. -// If sign > 0, IsInf reports whether f is positive infinity. -// If sign < 0, IsInf reports whether f is negative infinity. -// If sign == 0, IsInf reports whether f is either infinity. -func IsInf(f float64, sign int) bool { return m.IsInf(f, sign) } - -// Sqrt returns the square root of x. -// -// Special cases are: -// -// Sqrt(+Inf) = +Inf -// Sqrt(±0) = ±0 -// Sqrt(x < 0) = NaN -// Sqrt(NaN) = NaN -func Sqrt(x float64) float64 { return m.Sqrt(x) } - -// Sin returns the sine of the radian argument x. -// -// Special cases are: -// -// Sin(±0) = ±0 -// Sin(±Inf) = NaN -// Sin(NaN) = NaN -func Sin(x float64) float64 { return float64(m.Sin(float64(x))) } - -// Cos returns the cosine of the radian argument x. -// -// Special cases are: -// -// Cos(±Inf) = NaN -// Cos(NaN) = NaN -func Cos(x float64) float64 { return float64(m.Cos(float64(x))) } - -// Abs returns the absolute value of x. -// -// Special cases are: -// -// Abs(±Inf) = +Inf -// Abs(NaN) = NaN -func Abs(x float64) float64 { return float64(m.Abs(float64(x))) } - -// Acos returns the arccosine, in radians, of x. -// -// Special case is: -// -// Acos(x) = NaN if x < -1 or x > 1 -func Acos(x float64) float64 { return float64(m.Acos(float64(x))) } - -// Asin returns the arcsine, in radians, of x. -// -// Special cases are: -// -// Asin(±0) = ±0 -// Asin(x) = NaN if x < -1 or x > 1 -func Asin(x float64) float64 { return float64(m.Asin(float64(x))) } - -// Asinh returns the inverse hyperbolic sine of x. -// -// Special cases are: -// -// Asinh(±0) = ±0 -// Asinh(±Inf) = ±Inf -// Asinh(NaN) = NaN -func Asinh(x float64) float64 { return float64(m.Asinh(float64(x))) } - -// Atan returns the arctangent, in radians, of x. -// -// Special cases are: -// -// Atan(±0) = ±0 -// Atan(±Inf) = ±Pi/2 -func Atan(x float64) float64 { return float64(m.Atan(float64(x))) } - -// Atan2 returns the arc tangent of y/x, using -// the signs of the two to determine the quadrant -// of the return value. -// -// Special cases are (in order): -// -// Atan2(y, NaN) = NaN -// Atan2(NaN, x) = NaN -// Atan2(+0, x>=0) = +0 -// Atan2(-0, x>=0) = -0 -// Atan2(+0, x<=-0) = +Pi -// Atan2(-0, x<=-0) = -Pi -// Atan2(y>0, 0) = +Pi/2 -// Atan2(y<0, 0) = -Pi/2 -// Atan2(+Inf, +Inf) = +Pi/4 -// Atan2(-Inf, +Inf) = -Pi/4 -// Atan2(+Inf, -Inf) = 3Pi/4 -// Atan2(-Inf, -Inf) = -3Pi/4 -// Atan2(y, +Inf) = 0 -// Atan2(y>0, -Inf) = +Pi -// Atan2(y<0, -Inf) = -Pi -// Atan2(+Inf, x) = +Pi/2 -// Atan2(-Inf, x) = -Pi/2 -func Atan2(y, x float64) float64 { return float64(m.Atan2(float64(y), float64(x))) } - -// Atanh returns the inverse hyperbolic tangent of x. -// -// Special cases are: -// -// Atanh(1) = +Inf -// Atanh(±0) = ±0 -// Atanh(-1) = -Inf -// Atanh(x) = NaN if x < -1 or x > 1 -// Atanh(NaN) = NaN -func Atanh(x float64) float64 { return float64(m.Atanh(float64(x))) } - -// Cbrt returns the cube root of x. -// -// Special cases are: -// -// Cbrt(±0) = ±0 -// Cbrt(±Inf) = ±Inf -// Cbrt(NaN) = NaN -func Cbrt(x float64) float64 { return float64(m.Cbrt(float64(x))) } - -// Ceil returns the least integer value greater than or equal to x. -// -// Special cases are: -// -// Ceil(±0) = ±0 -// Ceil(±Inf) = ±Inf -// Ceil(NaN) = NaN -func Ceil(x float64) float64 { return float64(m.Ceil(float64(x))) } - -// Copysign returns a value with the magnitude -// of x and the sign of y. -func Copysign(x, y float64) float64 { return float64(m.Copysign(float64(x), float64(y))) } - -// Cosh returns the hyperbolic cosine of x. -// -// Special cases are: -// Cosh(±0) = 1 -// Cosh(±Inf) = +Inf -// Cosh(NaN) = NaN -//func Cosh(x float64) float64 { return float64(m.Cosh(float64(x))) } - -// Dim returns the maximum of x-y or 0. -// -// Special cases are: -// -// Dim(+Inf, +Inf) = NaN -// Dim(-Inf, -Inf) = NaN -// Dim(x, NaN) = Dim(NaN, x) = NaN -func Dim(x, y float64) float64 { return float64(m.Dim(float64(x), float64(y))) } - -// Erf returns the error function of x. -// -// Special cases are: -// -// Erf(+Inf) = 1 -// Erf(-Inf) = -1 -// Erf(NaN) = NaN -func Erf(x float64) float64 { return float64(m.Erf(float64(x))) } - -// Erfc returns the complementary error function of x. -// -// Special cases are: -// -// Erfc(+Inf) = 0 -// Erfc(-Inf) = 2 -// Erfc(NaN) = NaN -func Erfc(x float64) float64 { return float64(m.Erfc(float64(x))) } - -// Exp returns e**x, the base-e exponential of x. -// -// Special cases are: -// -// Exp(+Inf) = +Inf -// Exp(NaN) = NaN -// -// Very large values overflow to 0 or +Inf. -// Very small values underflow to 1. -func Exp(x float64) float64 { return float64(m.Exp(float64(x))) } - -// Exp2 returns 2**x, the base-2 exponential of x. -// -// Special cases are the same as Exp. -func Exp2(x float64) float64 { return float64(m.Exp2(float64(x))) } - -// Expm1 returns e**x - 1, the base-e exponential of x minus 1. -// It is more accurate than Exp(x) - 1 when x is near zero. -// -// Special cases are: -// -// Expm1(+Inf) = +Inf -// Expm1(-Inf) = -1 -// Expm1(NaN) = NaN -// -// Very large values overflow to -1 or +Inf. -func Expm1(x float64) float64 { return float64(m.Expm1(float64(x))) } - -// Float32bits returns the IEEE 754 binary representation of f. -func Float32bits(f float32) uint32 { return m.Float32bits(f) } - -// Float32frombits returns the floating point number corresponding -// to the IEEE 754 binary representation b. -func Float32frombits(b uint32) float32 { return m.Float32frombits(b) } - -// Float64bits returns the IEEE 754 binary representation of f. -func Float64bits(f float64) uint64 { return m.Float64bits(f) } - -// Float64frombits returns the floating point number corresponding -// the IEEE 754 binary representation b. -func Float64frombits(b uint64) float64 { return m.Float64frombits(b) } - -// Floor returns the greatest integer value less than or equal to x. -// -// Special cases are: -// -// Floor(±0) = ±0 -// Floor(±Inf) = ±Inf -// Floor(NaN) = NaN -func Floor(x float64) float64 { return float64(m.Floor(float64(x))) } - -// Frexp breaks f into a normalized fraction -// and an integral power of two. -// It returns frac and exp satisfying f == frac × 2**exp, -// with the absolute value of frac in the interval [½, 1). -// -// Special cases are: -// -// Frexp(±0) = ±0, 0 -// Frexp(±Inf) = ±Inf, 0 -// Frexp(NaN) = NaN, 0 -func Frexp(f float64) (frac float64, exp int) { - fr, exp := m.Frexp(float64(f)) - return float64(fr), exp -} - -// Gamma returns the Gamma function of x. -// -// Special cases are: -// -// Gamma(+Inf) = +Inf -// Gamma(+0) = +Inf -// Gamma(-0) = -Inf -// Gamma(x) = NaN for integer x < 0 -// Gamma(-Inf) = NaN -// Gamma(NaN) = NaN -func Gamma(x float64) float64 { return float64(m.Gamma(float64(x))) } - -// Hypot returns Sqrt(p*p + q*q), taking care to avoid -// unnecessary overflow and underflow. -// -// Special cases are: -// -// Hypot(±Inf, q) = +Inf -// Hypot(p, ±Inf) = +Inf -// Hypot(NaN, q) = NaN -// Hypot(p, NaN) = NaN -func Hypot(p, q float64) float64 { return float64(m.Hypot(float64(p), float64(q))) } - -// J0 returns the order-zero Bessel function of the first kind. -// -// Special cases are: -// -// J0(±Inf) = 0 -// J0(0) = 1 -// J0(NaN) = NaN -func J0(x float64) float64 { return float64(m.J0(float64(x))) } - -// J1 returns the order-one Bessel function of the first kind. -// -// Special cases are: -// -// J1(±Inf) = 0 -// J1(NaN) = NaN -func J1(x float64) float64 { return float64(m.J1(float64(x))) } - -// Jn returns the order-n Bessel function of the first kind. -// -// Special cases are: -// -// Jn(n, ±Inf) = 0 -// Jn(n, NaN) = NaN -func Jn(n int, x float64) float64 { return float64(m.Jn(n, float64(x))) } - -// Ldexp is the inverse of Frexp. -// It returns frac × 2**exp. -// -// Special cases are: -// -// Ldexp(±0, exp) = ±0 -// Ldexp(±Inf, exp) = ±Inf -// Ldexp(NaN, exp) = NaN -func Ldexp(frac float64, exp int) float64 { return float64(m.Ldexp(float64(frac), exp)) } - -// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x). -// -// Special cases are: -// -// Lgamma(+Inf) = +Inf -// Lgamma(0) = +Inf -// Lgamma(-integer) = +Inf -// Lgamma(-Inf) = -Inf -// Lgamma(NaN) = NaN -func Lgamma(x float64) (lgamma float64, sign int) { - l, sign := m.Lgamma(float64(x)) - return float64(l), sign -} - -// Log returns the natural logarithm of x. -// -// Special cases are: -// -// Log(+Inf) = +Inf -// Log(0) = -Inf -// Log(x < 0) = NaN -// Log(NaN) = NaN -func Log(x float64) float64 { return float64(m.Log(float64(x))) } - -// Log10 returns the decimal logarithm of x. -// The special cases are the same as for Log. -func Log10(x float64) float64 { return float64(m.Log10(float64(x))) } - -// Log1p returns the natural logarithm of 1 plus its argument x. -// It is more accurate than Log(1 + x) when x is near zero. -// -// Special cases are: -// -// Log1p(+Inf) = +Inf -// Log1p(±0) = ±0 -// Log1p(-1) = -Inf -// Log1p(x < -1) = NaN -// Log1p(NaN) = NaN -func Log1p(x float64) float64 { return float64(m.Log1p(float64(x))) } - -// Log2 returns the binary logarithm of x. -// The special cases are the same as for Log. -func Log2(x float64) float64 { return float64(m.Log2(float64(x))) } - -// Max returns the larger of x or y. -// -// Special cases are: -// -// Max(x, +Inf) = Max(+Inf, x) = +Inf -// Max(x, NaN) = Max(NaN, x) = NaN -// Max(+0, ±0) = Max(±0, +0) = +0 -// Max(-0, -0) = -0 -func Max(x, y float64) float64 { return float64(m.Max(float64(x), float64(y))) } - -// Min returns the smaller of x or y. -// -// Special cases are: -// -// Min(x, -Inf) = Min(-Inf, x) = -Inf -// Min(x, NaN) = Min(NaN, x) = NaN -// Min(-0, ±0) = Min(±0, -0) = -0 -func Min(x, y float64) float64 { return float64(m.Min(float64(x), float64(y))) } - -// Mod returns the floating-point remainder of x/y. -// The magnitude of the result is less than y and its -// sign agrees with that of x. -// -// Special cases are: -// -// Mod(±Inf, y) = NaN -// Mod(NaN, y) = NaN -// Mod(x, 0) = NaN -// Mod(x, ±Inf) = x -// Mod(x, NaN) = NaN -func Mod(x, y float64) float64 { return float64(m.Mod(float64(x), float64(y))) } - -// Modf returns integer and fractional floating-point numbers -// that sum to f. Both values have the same sign as f. -// -// Special cases are: -// -// Modf(±Inf) = ±Inf, NaN -// Modf(NaN) = NaN, NaN -func Modf(f float64) (int float64, frac float64) { - i, fr := m.Modf(float64(f)) - return float64(i), float64(fr) -} - -// Nextafter64 returns the next representable float64 value after x towards y. -// -// Special cases are: -// -// Nextafter(x, x) = x -// Nextafter(NaN, y) = NaN -// Nextafter(x, NaN) = NaN -func Nextafter(x, y float64) (r float64) { return m.Nextafter(x, y) } - -// Pow returns x**y, the base-x exponential of y. -// -// Special cases are (in order): -// -// Pow(x, ±0) = 1 for any x -// Pow(1, y) = 1 for any y -// Pow(x, 1) = x for any x -// Pow(NaN, y) = NaN -// Pow(x, NaN) = NaN -// Pow(±0, y) = ±Inf for y an odd integer < 0 -// Pow(±0, -Inf) = +Inf -// Pow(±0, +Inf) = +0 -// Pow(±0, y) = +Inf for finite y < 0 and not an odd integer -// Pow(±0, y) = ±0 for y an odd integer > 0 -// Pow(±0, y) = +0 for finite y > 0 and not an odd integer -// Pow(-1, ±Inf) = 1 -// Pow(x, +Inf) = +Inf for |x| > 1 -// Pow(x, -Inf) = +0 for |x| > 1 -// Pow(x, +Inf) = +0 for |x| < 1 -// Pow(x, -Inf) = +Inf for |x| < 1 -// Pow(+Inf, y) = +Inf for y > 0 -// Pow(+Inf, y) = +0 for y < 0 -// Pow(-Inf, y) = Pow(-0, -y) -// Pow(x, y) = NaN for finite x < 0 and finite non-integer y -func Pow(x, y float64) float64 { return float64(m.Pow(float64(x), float64(y))) } - -// Pow10 returns 10**e, the base-10 exponential of e. -// -// Special cases are: -// -// Pow10(e) = +Inf for e > 309 -// Pow10(e) = 0 for e < -324 -func Pow10(e int) float64 { return float64(m.Pow10(e)) } - -// Remainder returns the IEEE 754 floating-point remainder of x/y. -// -// Special cases are: -// -// Remainder(±Inf, y) = NaN -// Remainder(NaN, y) = NaN -// Remainder(x, 0) = NaN -// Remainder(x, ±Inf) = x -// Remainder(x, NaN) = NaN -func Remainder(x, y float64) float64 { return float64(m.Remainder(float64(x), float64(y))) } - -// Signbit returns true if x is negative or negative zero. -func Signbit(x float64) bool { return m.Signbit(float64(x)) } - -// Sincos returns Sin(x), Cos(x). -// -// Special cases are: -// -// Sincos(±0) = ±0, 1 -// Sincos(±Inf) = NaN, NaN -// Sincos(NaN) = NaN, NaN -func Sincos(x float64) (sin, cos float64) { - s, c := m.Sincos(float64(x)) - return float64(s), float64(c) -} - -// Sinh returns the hyperbolic sine of x. -// -// Special cases are: -// -// Sinh(±0) = ±0 -// Sinh(±Inf) = ±Inf -// Sinh(NaN) = NaN -func Sinh(x float64) float64 { return float64(m.Sinh(float64(x))) } - -// Tan returns the tangent of the radian argument x. -// -// Special cases are: -// -// Tan(±0) = ±0 -// Tan(±Inf) = NaN -// Tan(NaN) = NaN -func Tan(x float64) float64 { return float64(m.Tan(float64(x))) } - -// Tanh returns the hyperbolic tangent of x. -// -// Special cases are: -// -// Tanh(±0) = ±0 -// Tanh(±Inf) = ±1 -// Tanh(NaN) = NaN -func Tanh(x float64) float64 { return float64(m.Tanh(float64(x))) } - -// Trunc returns the integer value of x. -// -// Special cases are: -// -// Trunc(±0) = ±0 -// Trunc(±Inf) = ±Inf -// Trunc(NaN) = NaN -func Trunc(x float64) float64 { return float64(m.Trunc(float64(x))) } - -// Y0 returns the order-zero Bessel function of the second kind. -// -// Special cases are: -// -// Y0(+Inf) = 0 -// Y0(0) = -Inf -// Y0(x < 0) = NaN -// Y0(NaN) = NaN -func Y0(x float64) float64 { return float64(m.Y0(float64(x))) } - -// Y1 returns the order-one Bessel function of the second kind. -// -// Special cases are: -// -// Y1(+Inf) = 0 -// Y1(0) = -Inf -// Y1(x < 0) = NaN -// Y1(NaN) = NaN -func Y1(x float64) float64 { return float64(m.Y1(float64(x))) } - -// Yn returns the order-n Bessel function of the second kind. -// -// Special cases are: -// -// Yn(n, +Inf) = 0 -// Yn(n > 0, 0) = -Inf -// Yn(n < 0, 0) = +Inf if n is odd, -Inf if n is even -// Y1(n, x < 0) = NaN -// Y1(n, NaN) = NaN -func Yn(n int, x float64) float64 { return float64(m.Yn(n, float64(x))) } diff --git a/algorithms/max.go b/algorithms/max.go deleted file mode 100644 index 478199fca1ded0aa83695106c37abe22cca946b5..0000000000000000000000000000000000000000 --- a/algorithms/max.go +++ /dev/null @@ -1,39 +0,0 @@ -package algorithms - -func Max_Go[T Number](x []T) T { - max := x[0] - for _, v := range x[1:] { - if v > max { - max = v - } - } - return max -} - -func ArgMax_Go[T Number](x []T) int { - max := x[0] - idx := 0 - for i, v := range x[1:] { - if v > max { - max = v - idx = 1 + i - } - } - return idx -} - -func Maximum_Go[T Number](x, y []T) { - for i := 0; i < len(x); i++ { - if y[i] > x[i] { - x[i] = y[i] - } - } -} - -func MaximumNumber_Go[T Number](x []T, a T) { - for i := 0; i < len(x); i++ { - if a > x[i] { - x[i] = a - } - } -} diff --git a/algorithms/min.go b/algorithms/min.go deleted file mode 100644 index ca467455968f258791b5b0ffe1eabb3ff82b8d10..0000000000000000000000000000000000000000 --- a/algorithms/min.go +++ /dev/null @@ -1,39 +0,0 @@ -package algorithms - -func Min_Go[T Number](x []T) T { - min := x[0] - for _, v := range x[1:] { - if v < min { - min = v - } - } - return min -} - -func ArgMin_Go[T Number](x []T) int { - min := x[0] - idx := 0 - for i, v := range x[1:] { - if v < min { - min = v - idx = 1 + i - } - } - return idx -} - -func Minimum_Go[T Number](x, y []T) { - for i := 0; i < len(x); i++ { - if y[i] < x[i] { - x[i] = y[i] - } - } -} - -func MinimumNumber_Go[T Number](x []T, a T) { - for i := 0; i < len(x); i++ { - if a < x[i] { - x[i] = a - } - } -} diff --git a/builtin.go b/builtin.go index a996824b966910b38b5b93cce1a780272da2681d..94d82328e15780f2d9b70199c4401dca3fe560c9 100644 --- a/builtin.go +++ b/builtin.go @@ -3,6 +3,7 @@ package pandas import ( gc "github.com/huandu/go-clone" "math" + "reflect" "strings" ) @@ -11,12 +12,16 @@ import ( // 全局变量定义 var ( - // Nil2Float nil指针转换float64 - Nil2Float = float64(0) + // Nil2Float64 nil指针转换float64 + Nil2Float64 = float64(0) + // Nil2Float32 nil指针转换float32 + Nil2Float32 = float32(0) ) func init() { - Nil2Float = math.NaN() + Nil2Float64 = math.NaN() + // 这个转换是对的, NaN对float32也有效 + Nil2Float32 = float32(Nil2Float64) } // NaN returns an IEEE 754 “not-a-number” value. @@ -24,7 +29,7 @@ func NaN() float64 { return math.NaN() } -// IsNan float64是否NaN +// IsNaN float64是否NaN func IsNaN(f float64) bool { return math.IsNaN(f) || math.IsInf(f, 0) } @@ -42,3 +47,8 @@ func IsEmpty(s string) bool { func clone(v any) any { return gc.Clone(v) } + +func isPoint(v any) bool { + kind := reflect.ValueOf(v).Kind() + return reflect.Pointer == kind +} diff --git a/builtin_test.go b/builtin_test.go index 2ed9525b2d3e1f1bfb43a28ca6c98329c5c3a165..543cb060677af60f772add15ffc84bcfcfa102cf 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -1,6 +1,9 @@ package pandas -import "testing" +import ( + "fmt" + "testing" +) func TestIsEmpty(t *testing.T) { type args struct { @@ -69,3 +72,15 @@ func TestIsEmpty(t *testing.T) { }) } } + +func TestPoint(t *testing.T) { + var p1 *int + fmt.Printf("*int = nil, result=%v\n", isPoint(p1)) + a := 1 + p1 = &a + fmt.Printf("*int = nil, result=%v\n", isPoint(p1)) + + var p2 *BigFloat + fmt.Printf("*BigFloat = nil, result=%v\n", isPoint(p2)) + +} diff --git a/generic.go b/generic.go index 381bc4ce74236394223be2f6ef58e7e5ebaad0d5..6224c91e4bd02f5cda7d50412f3e65459ff77e76 100644 --- a/generic.go +++ b/generic.go @@ -183,7 +183,7 @@ func (self *NDFrame) apply(f func(idx int, v any)) { vk := vv.Kind() switch vk { case reflect.Invalid: // {interface} nil - //series.assign(idx, size, Nil2Float) + //series.assign(idx, size, Nil2Float64) case reflect.Slice: // 切片, 不定长 for i := 0; i < vv.Len(); i++ { tv := vv.Index(i).Interface() @@ -300,7 +300,7 @@ func (self *NDFrame) Shift(periods int) Series { var d Series d = clone(self).(Series) //return Shift[float64](&d, periods, func() float64 { - // return Nil2Float + // return Nil2Float64 //}) switch values := self.values.(type) { case []bool: @@ -314,11 +314,11 @@ func (self *NDFrame) Shift(periods int) Series { }) case []int64: return Shift[int64](&d, periods, func() int64 { - return Nil2Int + return Nil2Int64 }) default: //case []float64: return Shift[float64](&d, periods, func() float64 { - return Nil2Float + return Nil2Float64 }) } } @@ -378,3 +378,58 @@ func (self *NDFrame) FillNa(v any, inplace bool) { } } } + +func (self *NDFrame) Max() any { + values := self.Values() + switch rows := values.(type) { + case []string: + max := "" + i := 0 + for idx, iv := range rows { + if StringIsNaN(iv) { + continue + } + if iv > max { + max = iv + i += 1 + } + _ = idx + } + if i > 0 { + return max + } + return StringNaN + case []int64: + max := int64(0) + //i := 0 + for idx, iv := range rows { + if Float64IsNaN(float64(iv)) { + continue + } + if iv > max { + max = iv + //i = idx + } + _ = idx + } + return max + case []float64: + max := float64(0) + i := 0 + for idx, iv := range rows { + if Float64IsNaN(iv) { + continue + } + if iv > max { + max = iv + i += 1 + } + _ = idx + } + if i > 0 { + return max + } + return Nil2Float64 + } + return Nil2Float64 +} diff --git a/generic_test.go b/generic_test.go index 5672e6bc6d506c2c85cf96ca62777a65021832b5..9c702ac0ee5413871cc6d5bec887b510817cdafe 100644 --- a/generic_test.go +++ b/generic_test.go @@ -61,6 +61,8 @@ func TestNDFrameNew(t *testing.T) { fmt.Println(nd1.Records()) nd11 := nd1.Subset(1, 2, true) fmt.Println(nd11.Records()) + fmt.Println(nd1.Max()) + fmt.Println(nd1.Rolling(5).Max()) nd12 := nd1.Rolling(5).Mean() d12 := nd12.Values() @@ -74,6 +76,9 @@ func TestNDFrameNew(t *testing.T) { // string d2 := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "nan", "12"} nd2 := NewNDFrame[string]("x", d2...) + fmt.Println(nd2) + nd21 := nd2.Rolling(5).Max() + fmt.Println(nd21) nd2.FillNa(0, true) fmt.Println(nd2) fmt.Println(nd2.Records()) diff --git a/series.go b/series.go index 3bfa2eb4fe65c569ab28c6c29e55ba7e757326b8..bca22c3adcee4122698f493e4a873416c3b69fd8 100644 --- a/series.go +++ b/series.go @@ -58,6 +58,8 @@ type Series interface { StdDev() float64 // FillNa Fill NA/NaN values using the specified method. FillNa(v any, inplace bool) + // Max 找出最大值 + Max() any } // NewSeries 指定类型创建序列 @@ -89,7 +91,7 @@ func GenericSeries[T GenericType](name string, values ...T) *Series { vk := vv.Kind() switch vk { //case reflect.Invalid: // {interface} nil - // series.assign(idx, size, Nil2Float) + // series.assign(idx, size, Nil2Float64) //case reflect.Slice: // 切片, 不定长 // for i := 0; i < vv.Len(); i++ { // tv := vv.Index(i).Interface() diff --git a/series_ewm.go b/series_ewm.go index 4d09adfa73d25d5e92605cb37f2cfc73ee0910de..0ece6285258e136f35c8a8316318961cc7cc571e 100644 --- a/series_ewm.go +++ b/series_ewm.go @@ -1,7 +1,6 @@ package pandas import ( - "gitee.com/quant1x/pandas/algorithms" "math" ) @@ -98,7 +97,7 @@ func (w ExponentialMovingWindow) Mean() Series { if w.param <= 0 { panic("halflife param must be > 0") } - alpha = 1 - algorithms.Exp(-math.Ln2/w.param) + alpha = 1 - math.Exp(-math.Ln2/w.param) } return w.applyMean(w.data, alpha) diff --git a/series_float64.go b/series_float64.go index 4f2a4fa2f020c5e81778dbc651ac29183f1bd92e..00c06a6c9c57a71240f369b245810e493363a338 100644 --- a/series_float64.go +++ b/series_float64.go @@ -1,10 +1,9 @@ package pandas import ( - "gitee.com/quant1x/pandas/algorithms" "gitee.com/quant1x/pandas/algorithms/avx2" - //"github.com/huandu/go-clone" "gonum.org/v1/gonum/stat" + "math" "reflect" ) @@ -38,7 +37,7 @@ func NewSeriesFloat64(name string, vals ...interface{}) *SeriesFloat64 { vk := vv.Kind() switch vk { case reflect.Invalid: // {interface} nil - series.assign(idx, size, Nil2Float) + series.assign(idx, size, Nil2Float64) case reflect.Slice: // 切片, 不定长 for i := 0; i < vv.Len(); i++ { tv := vv.Index(i).Interface() @@ -113,7 +112,7 @@ func (self *SeriesFloat64) Shift(periods int) Series { var d Series d = clone(self).(Series) return Shift[float64](&d, periods, func() float64 { - return Nil2Float + return Nil2Float64 }) } @@ -133,7 +132,7 @@ func (self *SeriesFloat64) oldShift(periods int) *Series { src []float64 ) - if shlen := int(algorithms.Abs(float64(periods))); shlen < len(values) { + if shlen := int(math.Abs(float64(periods))); shlen < len(values) { if periods > 0 { naVals = values[:shlen] dst = values[shlen:] @@ -180,7 +179,7 @@ func (self *SeriesFloat64) Records() []string { for i := 0; i < self.Len(); i++ { //e := self.elements.Elem(i) e := self.Data[i] - ret[i] = float2String(e) + ret[i] = float64ToString(e) } return ret } diff --git a/series_float64_test.go b/series_float64_test.go index 920ca11334e435ddb897e20d914e80ccc610a295..371c9fb3cc30b1bc4679f5c8f58c27efca0a3906 100644 --- a/series_float64_test.go +++ b/series_float64_test.go @@ -20,7 +20,7 @@ func TestNewSeriesFloat64(t *testing.T) { s3 := s1.Repeat(1, 2) fmt.Println(s3.Values()) - s4 := NewSeriesFloat64("x", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + s4 := NewSeriesFloat64("x", []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) d4 := s4.Rolling(5).Mean() fmt.Printf("d4 = %+v\n", d4.Values()) diff --git a/series_int64.go b/series_int64.go index 588020963c6799085c1c9022a969db97b95e05e6..4b2dbb3da7ccbd0e6e59e3f0fb6e878e4a0a2b9b 100644 --- a/series_int64.go +++ b/series_int64.go @@ -134,7 +134,7 @@ func (self *SeriesInt64) Records() []string { ret := make([]string, self.Len()) for i := 0; i < self.Len(); i++ { e := self.Data[i] - ret[i] = int2String(e) + ret[i] = int64ToString(e) } return ret } diff --git a/series_number.go b/series_number.go index 78e42f8f4eae54923f33a4b2b45aaa11f4871e61..7f247d97bfa565542d20bad322c3c8fea855875b 100644 --- a/series_number.go +++ b/series_number.go @@ -1,9 +1,159 @@ package pandas -import "gitee.com/quant1x/pandas/algorithms" +import ( + "gitee.com/quant1x/pandas/algorithms/avx2" + "math/big" +) + +type BigFloat = big.Float // 预留将来可能扩展float + +type Number8 interface { + ~int8 | ~uint8 +} + +type Number16 interface { + ~int16 | ~uint16 +} + +type Number32 interface { + ~int32 | ~uint32 | float32 +} + +type Number64 interface { + ~int64 | ~uint64 | float64 +} + +type Float interface { + ~float32 | ~float64 +} + +// Number int和uint的长度取决于CPU是多少位 +type Number interface { + Number8 | Number16 | Number32 | Number64 | Float | int | uint +} + +//const ( +// True2Float32 float32 = float32(1) // true转float32 +// False2Float32 float32 = float32(0) // false转float32 +// StringTrue2Float32 float32 = float32(1) // 字符串true转float32 +// StringFalse2Float32 float32 = float32(0) // 字符串false转float32 +//) // Mean gonum.org/v1/gonum/stat不支持整型, 每次都要转换有点难受啊 -func Mean[T algorithms.Number](x []T) float64 { - d := algorithms.Mean_Go(x) - return float64(d) +func Mean[T Number](x []T) float64 { + d := numberToFloat64(x) + s := avx2.Mean(d) + return float64(s) +} + +// any转number +func value_to_number[T Number](v any, bool2t func(b bool) T, string2t func(s string, v any) T) T { + switch val := v.(type) { + case int8: + return T(val) + case uint8: + return T(val) + case int16: + return T(val) + case uint16: + return T(val) + case int32: + return T(val) + case uint32: + return T(val) + case int64: + return T(val) + case uint64: + return T(val) + case int: + return T(val) + case uint: + return T(val) + case float32: + return T(val) + case float64: + return T(val) + case bool: + return bool2t(val) + case string: + return string2t(val, v) + } + return T(0) +} + +// 指针转number +func point_to_number[T Number](v any, nil2t T, bool2t func(b bool) T, string2t func(s string, v any) T) T { + switch val := v.(type) { + case *int8: + if val == nil { + return nil2t + } + return T(*val) + case *uint8: + if val == nil { + return nil2t + } + return T(*val) + case *int16: + if val == nil { + return nil2t + } + return T(*val) + case *uint16: + if val == nil { + return nil2t + } + return T(*val) + case *int32: + if val == nil { + return nil2t + } + return T(*val) + case *uint32: + if val == nil { + return nil2t + } + return T(*val) + case *int64: + if val == nil { + return nil2t + } + return T(*val) + case *uint64: + if val == nil { + return nil2t + } + return T(*val) + case *int: + if val == nil { + return nil2t + } + return T(*val) + case *uint: + if val == nil { + return nil2t + } + return T(*val) + case *float32: + if val == nil { + return nil2t + } + return T(*val) + case *float64: + if val == nil { + return nil2t + } + return T(*val) + case *bool: + if val == nil { + return nil2t + } + return bool2t(*val) + case *string: + if val == nil { + return nil2t + } + return string2t(*val, v) + } + return T(0) } diff --git a/series_rolling.go b/series_rolling.go index 7109c00c8165923b934ad56444fe29cb89662bf6..cad43ab342ca9126a1b91808a2440b128fda58d2 100644 --- a/series_rolling.go +++ b/series_rolling.go @@ -41,3 +41,28 @@ func (r RollingWindow) StdDev() (s Series) { return } + +func (r RollingWindow) Max() any { + var fs []float64 + var is []int64 + var ss []string + for _, block := range r.getBlocks() { + //d = append(d, block.Max()) + v := block.Max() + switch val := v.(type) { + case float64: + fs = append(fs, val) + case int64: + is = append(is, val) + case string: + ss = append(ss, val) + } + } + if len(ss) > 0 { + return ss + } else if len(is) > 0 { + return is + } else { + return fs + } +} diff --git a/slice_float32.go b/slice_float32.go new file mode 100644 index 0000000000000000000000000000000000000000..e27acaf2feecce52cf3705049ee7962d50768d05 --- /dev/null +++ b/slice_float32.go @@ -0,0 +1,65 @@ +package pandas + +func slice_any_to_float32[T Number](s []T) []float32 { + count := len(s) + if count == 0 { + return []float32{} + } + d := make([]float32, count) + for idx, iv := range s { + // 强制转换 + d[idx] = float32(iv) + } + return d +} + +// any输入只能是一维slice或者数组 +func sliceToFloat32(v any) []float32 { + var vs []float32 + switch values := v.(type) { + case []int8: + return slice_any_to_float32(values) + case []uint8: + return slice_any_to_float32(values) + case []int16: + return slice_any_to_float32(values) + case []uint16: + return slice_any_to_float32(values) + case []int32: + return slice_any_to_float32(values) + case []uint32: + return slice_any_to_float32(values) + case []int64: + return slice_any_to_float32(values) + case []uint64: + return slice_any_to_float32(values) + case []int: + return slice_any_to_float32(values) + case []uint: + return slice_any_to_float32(values) + case []float32: + // TODO:直接返回会不会有问题 + return values + case []float64: + return slice_any_to_float32(values) + case []bool: + count := len(values) + if count == 0 { + return []float32{} + } + vs = make([]float32, count) + for idx, iv := range values { + vs[idx] = boolToFloat32(iv) + } + case []string: + count := len(values) + if count == 0 { + return []float32{} + } + vs = make([]float32, count) + for idx, iv := range values { + vs[idx] = float32(AnyToFloat64(iv)) + } + } + return []float32{} +} diff --git a/slice_float64.go b/slice_float64.go new file mode 100644 index 0000000000000000000000000000000000000000..80e9925cdafdf43a793f8a09448f6372a7cfb72f --- /dev/null +++ b/slice_float64.go @@ -0,0 +1,47 @@ +package pandas + +func slice_any_to_float64[T Number](s []T) []float64 { + count := len(s) + if count == 0 { + return []float64{} + } + d := make([]float64, count) + for idx, iv := range s { + d[idx] = float64(iv) + } + return d +} + +// any输入只能是一维slice或者数组 +func numberToFloat64(v any) []float64 { + var vs []float64 + switch values := v.(type) { + case []float64: + return values + case []int64: + return slice_any_to_float64(values) + case []int32: + return slice_any_to_float64(values) + case []int: + return slice_any_to_float64(values) + case []bool: + count := len(values) + if count == 0 { + return []float64{} + } + vs = make([]float64, count) + for idx, iv := range values { + vs[idx] = AnyToFloat64(iv) + } + case []string: + count := len(values) + if count == 0 { + return []float64{} + } + vs = make([]float64, count) + for idx, iv := range values { + vs[idx] = AnyToFloat64(iv) + } + } + return vs +} diff --git a/type_bool.go b/type_bool.go index b0a546fad9fb5aafd57b5c30c214183c286726fc..3eee110bd8dad7d30e777fdbfe988ac222f4e2fc 100644 --- a/type_bool.go +++ b/type_bool.go @@ -6,13 +6,16 @@ import ( ) const ( - Nil2Bool = false // 空指针转int64 - BoolNaN = false // int64 无效值 - True2Bool = true // true转int64 - False2Bool = false // false 转int64 - StringBad2Bool = false // 字符串解析int64异常 - StringTrue2Bool = true // 字符串true转int64 - StringFalse2Bool = false // 字符串false转int64 + Nil2Bool = false // 空指针转bool + BoolNaN = false // bool 无效值 + True2Bool = true // true转bool + False2Bool = false // false 转bool + True2Float32 float32 = float32(1) // true转float32 + False2Float32 float32 = float32(0) // false转float32 + + StringBad2Bool = false // 字符串解析bool异常 + StringTrue2Bool = true // 字符串true转bool + StringFalse2Bool = false // 字符串false转bool ) // AnyToBool any转换bool @@ -135,3 +138,26 @@ func float2Bool[T ~float32 | float64](f T) bool { } return true } + +// bool转float32 +func boolToFloat32(b bool) float32 { + if b { + return True2Float32 + } + return False2Float32 +} + +// bool转float32 +func boolToFloat64(b bool) float64 { + if b { + return True2Float64 + } + return False2Float64 +} + +func boolToInt64(b bool) int64 { + if b { + return True2Int64 + } + return False2Int64 +} diff --git a/type_float32.go b/type_float32.go new file mode 100644 index 0000000000000000000000000000000000000000..7b7e774c2e6537437d1303e9624c3bd154d1bf2e --- /dev/null +++ b/type_float32.go @@ -0,0 +1,65 @@ +package pandas + +import ( + "fmt" + "github.com/mymmsc/gox/logger" + "math" + "strconv" +) + +const ( + MaxFloat32 = math.MaxFloat32 // float32最大值 + StringTrue2Float32 float32 = float32(1) // 字符串true转float32 + StringFalse2Float32 float32 = float32(0) // 字符串false转float32 +) + +// Float32IsNaN 判断float32是否NaN +func Float32IsNaN(f float32) bool { + return IsNaN(float64(f)) +} + +// ParseFloat32 字符串转float32 +func ParseFloat32(s string, v any) float32 { + defer func() { + // 解析失败以后输出日志, 以备检查 + if err := recover(); err != nil { + logger.Errorf("ParseFloat32 %+v, error=%+v\n", v, err) + } + }() + + if IsEmpty(s) { + // TODO:NaN是针对64位, 这样直接转换应该有问题, 需要进一步确认 + return Nil2Float32 + } + if isTrue(s) { + return StringTrue2Float32 + } else if isFalse(s) { + return StringFalse2Float32 + } + + f, err := strconv.ParseFloat(s, 32) + if err == nil { + return float32(f) + } + if IgnoreParseExceptions { + return Nil2Float32 + } + _ = v.(float32) // Intentionally panic + return Nil2Float32 +} + +// float32转string +func float32ToString(v float32) string { + if Float32IsNaN(v) { + return StringNaN + } + return fmt.Sprintf("%f", v) +} + +func AnyToFloat32(v any) float32 { + if isPoint(v) { + return point_to_number[float32](v, Nil2Float32, boolToFloat32, ParseFloat32) + } + f := value_to_number[float32](v, boolToFloat32, ParseFloat32) + return f +} diff --git a/type_float32_test.go b/type_float32_test.go new file mode 100644 index 0000000000000000000000000000000000000000..aef3611de7fd18c57e55e96b827158f39bfc5a34 --- /dev/null +++ b/type_float32_test.go @@ -0,0 +1,381 @@ +package pandas + +import ( + "fmt" + "testing" +) + +func Test_point_to_1float32(t *testing.T) { + var p1 *int8 + f1 := AnyToFloat32(p1) + fmt.Printf("*int8 to float32=%f\n", f1) + + var v1 int8 = 1 + p1 = &v1 + f1 = AnyToFloat32(p1) + fmt.Printf("*int8 to float32=%f\n", f1) +} + +func Test_point_to_float32(t *testing.T) { + type args struct { + v any + } + + // 指针声明 + var pInt8 *int8 + var pUint8 *uint8 + var pInt16 *int16 + var pUint16 *uint16 + var pInt32 *int32 + var pUint32 *uint32 + var pInt64 *int64 + var pUint64 *uint64 + var pInt *int + var pUint *uint + var pFloat32 *float32 + var pFloat64 *float64 + var pBoolTrue *bool + var pBoolFalse *bool + var pStr1 *string + var pStr2 *string + + vInt8 := int8(1) + pInt8 = &vInt8 + vUint8 := uint8(1) + pUint8 = &vUint8 + + vInt16 := int16(1) + pInt16 = &vInt16 + vUint16 := uint16(1) + pUint16 = &vUint16 + + vInt32 := int32(1) + pInt32 = &vInt32 + vUint32 := uint32(1) + pUint32 = &vUint32 + + vInt64 := int64(1) + pInt64 = &vInt64 + vUint64 := uint64(1) + pUint64 = &vUint64 + + vInt := int(1) + pInt = &vInt + vUint := uint(1) + pUint = &vUint + + vFloat32 := float32(1) + pFloat32 = &vFloat32 + vFloat64 := float64(1) + pFloat64 = &vFloat64 + + vBoolTrue := true + pBoolTrue = &vBoolTrue + vBoolFalse := false + pBoolFalse = &vBoolFalse + + vStr1 := "abc" + pStr1 = &vStr1 + vStr2 := "1.23" + pStr2 = &vStr2 + + tests := []struct { + name string + args args + want float32 + }{ + { + name: "T01: int8", + args: args{ + pInt8, + }, + want: float32(1), + }, + { + name: "T02: uint8", + args: args{ + pUint8, + }, + want: float32(1), + }, + { + name: "T03: int16", + args: args{ + pInt16, + }, + want: float32(1), + }, + { + name: "T04: uint16", + args: args{ + pUint16, + }, + want: float32(1), + }, + { + name: "T05: int32", + args: args{ + pInt32, + }, + want: float32(1), + }, + { + name: "T06: uint32", + args: args{ + pUint32, + }, + want: float32(1), + }, + { + name: "T07: int64", + args: args{ + pInt64, + }, + want: float32(1), + }, + { + name: "T08: uint64", + args: args{ + pUint64, + }, + want: float32(1), + }, + { + name: "T09: int", + args: args{ + pInt, + }, + want: float32(1), + }, + { + name: "T10: uint", + args: args{ + pUint, + }, + want: float32(1), + }, + { + name: "T11: float32", + args: args{ + pFloat32, + }, + want: float32(1), + }, + { + name: "T12: float64", + args: args{ + pFloat64, + }, + want: float32(1), + }, + { + name: "T13: true", + args: args{ + pBoolTrue, + }, + want: float32(1), + }, + { + name: "T14: false", + args: args{ + pBoolFalse, + }, + want: float32(0), + }, + { + name: "T15: str1", + args: args{ + pStr1, + }, + want: Nil2Float32, + }, + { + name: "T16: str2", + args: args{ + pStr2, + }, + want: float32(1.23), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + //got := point_to_float32(tt.args.v) + //if got != tt.want { + // if !IsNaN(float64(tt.want)) { + // t.Errorf("point_to_float32() = %v, want %v", got, tt.want) + // } else if !IsNaN(float64(got)) { + // t.Errorf("point_to_float32() = %v, want %v", got, tt.want) + // } + //} + if got := AnyToFloat32(tt.args.v); got != tt.want && !(IsNaN(float64(tt.want)) && IsNaN(float64(got))) { + t.Errorf("AnyToFloat32() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_value_to_float32(t *testing.T) { + type args struct { + v any + } + + vInt8 := int8(1) + vUint8 := uint8(1) + + vInt16 := int16(1) + vUint16 := uint16(1) + + vInt32 := int32(1) + vUint32 := uint32(1) + + vInt64 := int64(1) + vUint64 := uint64(1) + + vInt := int(1) + vUint := uint(1) + + vFloat32 := float32(1) + vFloat64 := float64(1) + + //vBoolTrue := true + //vBoolFalse := false + + vStr1 := "abc" + vStr2 := "1.23" + + // 组装测试用例 + tests := []struct { + name string + args args + want float32 + }{ + { + name: "T01: int8", + args: args{ + vInt8, + }, + want: float32(1), + }, + { + name: "T02: uint8", + args: args{ + vUint8, + }, + want: float32(1), + }, + { + name: "T03: int16", + args: args{ + vInt16, + }, + want: float32(1), + }, + { + name: "T04: uint16", + args: args{ + vUint16, + }, + want: float32(1), + }, + { + name: "T05: int32", + args: args{ + vInt32, + }, + want: float32(1), + }, + { + name: "T06: uint32", + args: args{ + vUint32, + }, + want: float32(1), + }, + { + name: "T07: int64", + args: args{ + vInt64, + }, + want: float32(1), + }, + { + name: "T08: uint64", + args: args{ + vUint64, + }, + want: float32(1), + }, + { + name: "T09: int", + args: args{ + vInt, + }, + want: float32(1), + }, + { + name: "T10: uint", + args: args{ + vUint, + }, + want: float32(1), + }, + { + name: "T11: float32", + args: args{ + vFloat32, + }, + want: float32(1), + }, + { + name: "T12: float64", + args: args{ + vFloat64, + }, + want: float32(1), + }, + { + name: "T13: true", + args: args{ + true, + }, + want: float32(1), + }, + { + name: "T14: false", + args: args{ + false, + }, + want: float32(0), + }, + { + name: "T15: str1", + args: args{ + vStr1, + }, + want: Nil2Float32, + }, + { + name: "T16: str2", + args: args{ + vStr2, + }, + want: float32(1.23), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + //got := value_to_float32(tt.args.v) + //if got != tt.want { + // if !IsNaN(float64(tt.want)) { + // t.Errorf("value_to_float32() = %v, want %v", got, tt.want) + // } else if !IsNaN(float64(got)) { + // t.Errorf("value_to_float32() = %v, want %v", got, tt.want) + // } + //} + if got := AnyToFloat32(tt.args.v); !(got == tt.want || (IsNaN(float64(tt.want)) && IsNaN(float64(got)))) { + t.Errorf("AnyToFloat32() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/type_float64.go b/type_float64.go index a437f49096a9257f2c9cb1681e3e6485a9f1a324..bd101c8ccb2f004e61ca2b2c1dcf06cc4ea215b8 100644 --- a/type_float64.go +++ b/type_float64.go @@ -2,105 +2,66 @@ package pandas import ( "fmt" + "github.com/mymmsc/gox/logger" + "math" "strconv" ) const ( - True2Float float64 = float64(1) // true转float64 - False2Float float64 = float64(0) - StringNil2Float float64 = float64(0) // deprecated: 字符串空指针转float64 - StringBad2Float float64 = float64(0) // deprecated: 字符串解析float64异常 - StringTrue2Float float64 = float64(1) // 字符串true转float64 - StringFalse2Float float64 = float64(0) // 字符串false转float64 + MaxFloat64 float64 = math.MaxFloat64 // float64最大值 + True2Float64 float64 = float64(1) // true转float64 + False2Float64 float64 = float64(0) // false转float64 + StringNil2Float float64 = float64(0) // deprecated: 字符串空指针转float64 + StringBad2Float float64 = float64(0) // deprecated: 字符串解析float64异常 + StringTrue2Float64 float64 = float64(1) // 字符串true转float64 + StringFalse2Float64 float64 = float64(0) // 字符串false转float64 ) -// AnyToFloat64 any转换float64 -func AnyToFloat64(v any) float64 { - switch val := v.(type) { - case nil: - return nan() - case *bool: - if val == nil { - return Nil2Float - } - if *val == true { - return True2Float - } - return False2Float - case bool: - if val == true { - return True2Float - } - return False2Float - case *int: - if val == nil { - return Nil2Float - } - return float64(*val) - case int: - return float64(val) - case *int64: - if val == nil { - return Nil2Float - } - return float64(*val) - case int64: - return float64(val) - case *float64: - if val == nil { - return Nil2Float - } - return *val - case float64: - return val - case *string: - if val == nil { - return Nil2Float - } - if IsEmpty(*val) { - return Nil2Float - } - if isTrue(*val) { - return StringTrue2Float - } else if isFalse(*val) { - return StringFalse2Float - } - f := ParseFloat(*val, v) - return f - case string: - if IsEmpty(val) { - return Nil2Float - } - if isTrue(val) { - return StringTrue2Float - } else if isFalse(val) { - return StringFalse2Float - } - f := ParseFloat(val, v) - return f - default: - f := ParseFloat(fmt.Sprintf("%v", v), v) - return f - } +// Float64IsNaN 判断float64是否NaN +func Float64IsNaN(f float64) bool { + return IsNaN(f) } -// ParseFloat 字符串转float64 +// ParseFloat64 字符串转float64 // 任意组合的nan字符串都会被解析成NaN -func ParseFloat(s string, v any) float64 { - f, err := strconv.ParseFloat(s, 64) - if err != nil { - if IgnoreParseExceptions { - f = Nil2Float - } else { - _ = v.(float64) // Intentionally panic +func ParseFloat64(s string, v any) float64 { + defer func() { + // 解析失败以后输出日志, 以备检查 + if err := recover(); err != nil { + logger.Errorf("ParseFloat64 %+v, error=%+v\n", v, err) } + }() + if IsEmpty(s) { + return Nil2Float64 } - return f + if isTrue(s) { + return StringTrue2Float64 + } else if isFalse(s) { + return StringFalse2Float64 + } + f, err := strconv.ParseFloat(s, 64) + if err == nil { + return f + } + if IgnoreParseExceptions { + return Nil2Float64 + } + _ = v.(float64) // Intentionally panic + return Nil2Float64 } -func float2String(v float64) string { +// float64转string +func float64ToString(v float64) string { if isNaN(v) { return StringNaN } return fmt.Sprintf("%f", v) } + +func AnyToFloat64(v any) float64 { + if isPoint(v) { + return point_to_number[float64](v, Nil2Float64, boolToFloat64, ParseFloat64) + } + f := value_to_number[float64](v, boolToFloat64, ParseFloat64) + return f +} diff --git a/type_float64_test.go b/type_float64_test.go index cc8066c7be0b3c69b19d2ba69845b27a8ed167fa..a4a06cf50742a239564972956e7b586cdbd59fcf 100644 --- a/type_float64_test.go +++ b/type_float64_test.go @@ -90,9 +90,9 @@ func TestParseFloat2Nan(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - //if got := ParseFloat(tt.args.s, tt.args.v); got != tt.want { - if got := ParseFloat(tt.args.s, tt.args.v); !math.IsNaN(got) { - t.Errorf("ParseFloat() = %v, want %v", got, tt.want) + //if got := ParseFloat64(tt.args.s, tt.args.v); got != tt.want { + if got := ParseFloat64(tt.args.s, tt.args.v); !math.IsNaN(got) { + t.Errorf("ParseFloat64() = %v, want %v", got, tt.want) } }) } diff --git a/type_int64.go b/type_int64.go index 32ebd054b128e1ca2b9041bceec1b19b5a04e4d4..510fd8f5b6bae2d718bf232cc8c86e40861a4cc5 100644 --- a/type_int64.go +++ b/type_int64.go @@ -7,112 +7,61 @@ import ( ) const ( - Nil2Int = int64(0) // 空指针转int64 - IntNaN = int64(0) // int64 无效值 - True2Int = int64(1) // true转int64 - False2Int = int64(0) // false 转int64 - StringBad2Int = int64(0) // 字符串解析int64异常 - StringTrue2Int = int64(1) // 字符串true转int64 - StringFalse2Int = int64(0) // 字符串false转int64 + Nil2Int64 = int64(0) // 空指针转int64 + IntNaN = int64(0) // int64 无效值 + True2Int64 = int64(1) // true转int64 + False2Int64 = int64(0) // false 转int64 + StringBad2Int64 = int64(0) // 字符串解析int64异常 + StringTrue2Int64 = int64(1) // 字符串true转int64 + StringFalse2Int64 = int64(0) // 字符串false转int64 ) -// AnyToInt64 any转换int64 -func AnyToInt64(v any) int64 { - switch val := v.(type) { - case nil: - return IntNaN - case *bool: - if val == nil { - return Nil2Int - } - if *val == true { - return True2Int - } - return False2Int - case bool: - if val == true { - return True2Int - } - return False2Int - case *int: - if val == nil { - return Nil2Int - } - return int64(*val) - case int: - return int64(val) - case *int64: - if val == nil { - return Nil2Int - } - return *val - case int64: - return val - case *float32: - if val == nil { - return Nil2Int - } - return int64(*val) - case float32: - return int64(val) - case *float64: - if val == nil { - return Nil2Int - } - return int64(*val) - case float64: - return int64(val) - case *string: - if val == nil { - return Nil2Int - } - if IsEmpty(*val) { - return Nil2Int - } - if isTrue(*val) { - return StringTrue2Int - } else if isFalse(*val) { - return StringFalse2Int - } - i := ParseInt(*val, v) - return i - case string: - if IsEmpty(val) { - return Nil2Int - } - if isTrue(val) { - return StringTrue2Int - } else if isFalse(val) { - return StringFalse2Int +// ParseInt64 解析int字符串, 尝试解析10进制和16进制 +func ParseInt64(s string, v any) int64 { + defer func() { + // 解析失败以后输出日志, 以备检查 + if err := recover(); err != nil { + logger.Errorf("ParseInt64 %+v, error=%+v\n", v, err) } - i := ParseInt(val, v) + }() + if IsEmpty(s) { + return Nil2Int64 + } + if isTrue(s) { + return StringTrue2Int64 + } else if isFalse(s) { + return StringFalse2Int64 + } + i, err := strconv.ParseInt(s, 10, 64) + if err == nil { return i - default: - i := ParseInt(fmt.Sprintf("%v", v), v) + } + // 解析失败继续解析16进制 + i, err = strconv.ParseInt(s, 16, 64) + if err == nil { return i } -} - -// ParseInt 解析int字符串, 尝试解析10进制和16进制 -func ParseInt(s string, v any) int64 { - i, err := strconv.ParseInt(s, 10, 64) - if err != nil { - i, err = strconv.ParseInt(s, 16, 64) - if err != nil { - logger.Errorf("%s, error=%+v\n", s, err) - if IgnoreParseExceptions { - i = StringBad2Int - } else { - _ = v.(int64) // Intentionally panic - } - } + logger.Errorf("%s, error=%+v\n", s, err) + if IgnoreParseExceptions { + i = StringBad2Int64 + } else { + _ = v.(int64) // Intentionally panic } return i } -func int2String(v int64) string { - if isNaN(float64(v)) { +func int64ToString(v int64) string { + if Float64IsNaN(float64(v)) { return StringNaN } return fmt.Sprint(v) } + +// AnyToInt64 any转换int64 +func AnyToInt64(v any) int64 { + if isPoint(v) { + return point_to_number[int64](v, Nil2Int64, boolToInt64, ParseInt64) + } + f := value_to_number[int64](v, boolToInt64, ParseInt64) + return f +} diff --git a/type_string.go b/type_string.go index 30c8d3d0d5ee5a2a4eaf5a7dbc9d986dad6a2949..5309cb92fe1826943ab8b400e47da9e1e9ea0251 100644 --- a/type_string.go +++ b/type_string.go @@ -44,37 +44,37 @@ func AnyToString(v any) string { if val == nil { return Nil2String } - return []string{strconv.FormatFloat(*val, 'G', -1, 64)}[0] + return strconv.FormatFloat(*val, 'G', -1, 64) case float64: - return []string{strconv.FormatFloat(val, 'G', -1, 64)}[0] + return strconv.FormatFloat(val, 'G', -1, 64) case *float32: if val == nil { return Nil2String } - return []string{strconv.FormatFloat(float64(*val), 'G', -1, 64)}[0] + return strconv.FormatFloat(float64(*val), 'G', -1, 64) case float32: - return []string{strconv.FormatFloat(float64(val), 'G', -1, 64)}[0] + return strconv.FormatFloat(float64(val), 'G', -1, 64) case *int64: if val == nil { return Nil2String } - return []string{strconv.FormatInt(*val, 10)}[0] + return strconv.FormatInt(*val, 10) case int64: - return []string{strconv.FormatInt(val, 10)}[0] + return strconv.FormatInt(val, 10) case *int: if val == nil { return Nil2String } - return []string{strconv.Itoa(*val)}[0] + return strconv.Itoa(*val) case int: - return []string{strconv.Itoa(val)}[0] + return strconv.Itoa(val) case *int32: if val == nil { return Nil2String } - return []string{strconv.FormatInt(int64(*val), 10)}[0] + return strconv.FormatInt(int64(*val), 10) case int32: - return []string{strconv.FormatInt(int64(val), 10)}[0] + return strconv.FormatInt(int64(val), 10) default: logger.Errorf("%s, error=The type is not recognized\n", v) _ = v.(string) // Intentionally panic