You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
10 KiB
281 lines
10 KiB
using Apewer.Internals;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Apewer
|
|
{
|
|
|
|
/// <summary>数值实用工具。</summary>
|
|
public static class NumberUtility
|
|
{
|
|
|
|
#region 随机数。
|
|
|
|
/// <summary>用于生成随机数的时钟位置。</summary>
|
|
private static int RandomSeed = 327680;
|
|
|
|
private static float RandomTimer()
|
|
{
|
|
var now = DateTime.Now;
|
|
return (float)((double)(checked((60 * now.Hour + now.Minute) * 60 + now.Second)) + (double)now.Millisecond / 1000.0);
|
|
}
|
|
|
|
private static void RandomInit()
|
|
{
|
|
float timer = RandomTimer();
|
|
int num1 = RandomSeed;
|
|
int num2 = BitConverter.ToInt32(BitConverter.GetBytes(timer), 0);
|
|
num2 = ((num2 & 65535) ^ num2 >> 16) << 8;
|
|
num1 = ((num1 & -16776961) | num2);
|
|
RandomSeed = num1;
|
|
}
|
|
|
|
/// <summary>生成不大于 1 的随机数,最小为 0。</summary>
|
|
public static float RandomFloat(float max = 1F)
|
|
{
|
|
RandomInit();
|
|
int num1 = RandomSeed;
|
|
if ((double)max != 0.0)
|
|
{
|
|
if ((double)max < 0.0)
|
|
{
|
|
num1 = BitConverter.ToInt32(BitConverter.GetBytes(max), 0);
|
|
long vnum2 = (long)num1;
|
|
vnum2 &= unchecked((long)((ulong)-1));
|
|
num1 = checked((int)(vnum2 + (vnum2 >> 24) & 16777215L));
|
|
}
|
|
num1 = checked((int)(unchecked((long)num1) * 1140671485L + 12820163L & 16777215L));
|
|
}
|
|
RandomSeed = num1;
|
|
return (float)num1 / 16777216f;
|
|
}
|
|
|
|
/// <summary>生成随机整数,包含最小值和最大值。</summary>
|
|
/// <param name="min">最小值。</param>
|
|
/// <param name="max">最大值。</param>
|
|
/// <returns></returns>
|
|
public static int RandomInteger(int max, int min = 0)
|
|
{
|
|
if (max < min)
|
|
{
|
|
var temp = max;
|
|
max = min;
|
|
min = temp;
|
|
}
|
|
float rate = (max - min + 1) * RandomFloat();
|
|
int result = min + (int)rate;
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Restrict 约束值范围。
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static T RestrictValue<T>(T origin, T min, T max) where T : IComparable
|
|
{
|
|
try
|
|
{
|
|
if (min.CompareTo(max) > 0) return origin;
|
|
|
|
if (origin.CompareTo(min) < 0) return min;
|
|
if (origin.CompareTo(max) > 0) return max;
|
|
return origin;
|
|
}
|
|
catch { }
|
|
|
|
return origin;
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Byte RestrictValue(Byte target, Byte min, Byte max)
|
|
{
|
|
return RestrictValue<Byte>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Int16 RestrictValue(Int16 target, Int16 min, Int16 max)
|
|
{
|
|
return RestrictValue<Int16>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Int32 RestrictValue(Int32 target, Int32 min, Int32 max)
|
|
{
|
|
return RestrictValue<Int32>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Int64 RestrictValue(Int64 target, Int64 min, Int64 max)
|
|
{
|
|
return RestrictValue<Int64>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Single RestrictValue(Single target, Single min, Single max)
|
|
{
|
|
return RestrictValue<Single>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Double RestrictValue(Double target, Double min, Double max)
|
|
{
|
|
return RestrictValue<Double>(target, min, max);
|
|
}
|
|
|
|
/// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
|
|
public static Decimal RestrictValue(Decimal target, Decimal min, Decimal max)
|
|
{
|
|
return RestrictValue<Decimal>(target, min, max);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>平均值。</summary>
|
|
public static double Average(params double[] values)
|
|
{
|
|
var amount = 0d;
|
|
foreach (var i in values) amount += i;
|
|
return amount / Convert.ToDouble(values.Length);
|
|
}
|
|
|
|
#region 最小值、最大值。
|
|
|
|
private static T GetMost<T>(Func<T, T, bool> replace, T[] values)
|
|
{
|
|
if (values == null) return default;
|
|
|
|
var length = values.LongLength;
|
|
if (length == 0L) return default;
|
|
if (length == 1L) return values[0L];
|
|
|
|
var most = values[0];
|
|
for (var i = 1L; i < length; i++)
|
|
{
|
|
var value = values[i];
|
|
if (value == null) continue;
|
|
if (most == null)
|
|
{
|
|
most = value;
|
|
}
|
|
else
|
|
{
|
|
var doReplace = replace(most, value);
|
|
if (doReplace) most = value;
|
|
}
|
|
}
|
|
return most;
|
|
}
|
|
|
|
// 无法输出正确结果。
|
|
// public static T GetMin<T>(params IComparable[] values)
|
|
// {
|
|
// var result = GetMost((a, b) => a.CompareTo(b) == 1, values);
|
|
// return result == null ? default : (T)result;
|
|
// }
|
|
|
|
// 无法输出正确结果。
|
|
// public static T GetMin<T>(params IComparable<T>[] values)
|
|
// {
|
|
// var result = GetMost((a, b) => a.CompareTo((T)b) == 1, values);
|
|
// return result == null ? default : (T)result;
|
|
// }
|
|
|
|
// 无法输出正确结果。
|
|
// public static T GetMax<T>(params IComparable[] values)
|
|
// {
|
|
// var result = GetMost((a, b) => a.CompareTo(b) == -1, values);
|
|
// return result == null ? default : (T)result;
|
|
// }
|
|
|
|
// 无法输出正确结果。
|
|
// public static T GetMax<T>(params IComparable<T>[] values)
|
|
// {
|
|
// var result = GetMost((a, b) => a.CompareTo((T)b) == -1, values);
|
|
// return result == null ? default : (T)result;
|
|
// }
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static byte Min(params byte[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static int Min(params int[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static long Min(params long[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static float Min(params float[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static double Min(params double[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最小值。</summary>
|
|
public static decimal Min(params decimal[] values) => GetMost((a, b) => a > b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static byte Max(params byte[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static int Max(params int[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static long Max(params long[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static float Max(params float[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static double Max(params double[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
/// <summary>最大值。</summary>
|
|
public static decimal Max(params decimal[] values) => GetMost((a, b) => a < b, values);
|
|
|
|
#endregion
|
|
|
|
/// <summary>Pearson Correlation Coefficient 皮尔逊相关系数。计算两个数组的相似度。数组长度不相等时,以 0 填充不足的长度。</summary>
|
|
/// <remarks>
|
|
/// <para>0.8 ~ 1.0 : 极强相关</para>
|
|
/// <para>0.6 ~ 0.8 : 强相关</para>
|
|
/// <para>0.4 ~ 0.6 : 中等程度相关</para>
|
|
/// <para>0.2 ~ 0.4 : 弱相关</para>
|
|
/// <para>0.0 ~ 0.2 : 极弱相关或无相关</para>
|
|
/// </remarks>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
public static double Pearson(double[] bytes1, double[] bytes2)
|
|
{
|
|
var length1 = bytes1 == null ? 0L : bytes1.LongLength;
|
|
var length2 = bytes2 == null ? 0L : bytes2.LongLength;
|
|
var length = Math.Max(length1, length2);
|
|
if (length < 1) return 1D;
|
|
|
|
var x = new double[length];
|
|
var y = new double[length];
|
|
for (var i = 0L; i < length; i++)
|
|
{
|
|
if (i < length1) x[i] = bytes1[i];
|
|
if (i < length2) y[i] = bytes2[i];
|
|
}
|
|
|
|
int n = x.Length; // 数组长度。
|
|
double s = 0d; // 分子。
|
|
double m1 = 0d, m2 = 0d; // 分母。
|
|
|
|
double xa = Average(x);
|
|
double ya = Average(y);
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
s += (x[i] - xa) * (y[i] - ya);
|
|
m1 += Math.Pow(x[i] - xa, 2);
|
|
m2 += Math.Pow(y[i] - ya, 2);
|
|
}
|
|
|
|
double r = s / (Math.Sqrt(m1) * Math.Sqrt(m2));
|
|
return r;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|