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.

435 lines
16 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. namespace Apewer
  8. {
  9. /// <summary>数值实用工具。</summary>
  10. public static class NumberUtility
  11. {
  12. #region 随机数。
  13. /// <summary>用于生成随机数的时钟位置。</summary>
  14. private static int RandomSeed = 327680;
  15. private static void RandomInit()
  16. {
  17. var now = DateTime.Now;
  18. var timer = (float)((double)(checked((60 * now.Hour + now.Minute) * 60 + now.Second)) + (double)now.Millisecond / 1000.0);
  19. int num1 = RandomSeed;
  20. int num2 = BitConverter.ToInt32(BitConverter.GetBytes(timer), 0);
  21. num2 = ((num2 & 65535) ^ num2 >> 16) << 8;
  22. num1 = (num1 & -16776961) | num2;
  23. RandomSeed = num1;
  24. }
  25. /// <summary>生成不大于 1 的随机数,最小为 0。</summary>
  26. public static float Random(float max = 1F)
  27. {
  28. RandomInit();
  29. int num1 = RandomSeed;
  30. if ((double)max != 0.0)
  31. {
  32. if ((double)max < 0.0)
  33. {
  34. num1 = BitConverter.ToInt32(BitConverter.GetBytes(max), 0);
  35. long vnum2 = (long)num1;
  36. vnum2 &= unchecked((long)((ulong)-1));
  37. num1 = checked((int)(vnum2 + (vnum2 >> 24) & 16777215L));
  38. }
  39. num1 = checked((int)(unchecked((long)num1) * 1140671485L + 12820163L & 16777215L));
  40. }
  41. RandomSeed = num1;
  42. return (float)num1 / 16777216f;
  43. }
  44. /// <summary>生成随机整数,包含最小值和最大值。</summary>
  45. /// <param name="min">最小值。</param>
  46. /// <param name="max">最大值。</param>
  47. /// <returns></returns>
  48. public static int Random(int max, int min = 0)
  49. {
  50. if (max == min) return max;
  51. if (max < min)
  52. {
  53. var temp = max;
  54. max = min;
  55. min = temp;
  56. }
  57. var rate = (max - min + 1) * Random();
  58. var result = min + (int)rate;
  59. return result;
  60. }
  61. /// <summary>对数组填充随机数。<br />0 &lt;= value &lt; 1.0</summary>
  62. public static void Random(float[] array, int offset = 0, int count = -1)
  63. {
  64. if (array == null) return;
  65. if (count == 0) return;
  66. var length = array.LongLength;
  67. var end = length;
  68. if (count > 0) end = offset + count;
  69. if (end > length) end = length;
  70. RandomInit();
  71. var max = 1.0;
  72. for (var i = offset; i < end; i++)
  73. {
  74. if (i < 0) continue;
  75. int num1 = RandomSeed;
  76. if ((double)max != 0.0)
  77. {
  78. if ((double)max < 0.0)
  79. {
  80. num1 = BitConverter.ToInt32(BitConverter.GetBytes(max), 0);
  81. long vnum2 = (long)num1;
  82. vnum2 &= unchecked((long)((ulong)-1));
  83. num1 = checked((int)(vnum2 + (vnum2 >> 24) & 16777215L));
  84. }
  85. num1 = checked((int)(unchecked((long)num1) * 1140671485L + 12820163L & 16777215L));
  86. }
  87. RandomSeed = num1;
  88. array[i] = (float)num1 / 16777216f;
  89. }
  90. }
  91. /// <summary>对数组填充随机数。<br />0 &lt;= value &lt;= 255</summary>
  92. public static void Random(byte[] array, int offset = 0, int count = -1) { }
  93. static ulong UuidGetSystemTime(DateTime dt)
  94. {
  95. /* UUID system time starts at October 15, 1582 */
  96. // const long TICKS_PER_CLOCK_TICK = 1000L;
  97. const long SECSPERDAY = 86400L;
  98. const long TICKSPERSEC = 10000000L;
  99. const long SECS_15_OCT_1582_TO_1601 = (17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY;
  100. const long TICKS_15_OCT_1582_TO_1601 = SECS_15_OCT_1582_TO_1601 * TICKSPERSEC;
  101. var ticks = dt.Ticks;
  102. ticks += (17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY;
  103. ticks += TICKS_15_OCT_1582_TO_1601;
  104. return default;
  105. }
  106. /// <summary>生成 GUID。</summary>
  107. static byte[] NewGuid()
  108. {
  109. // DWORD Data1 // 随机数
  110. // WORD Data2 // 和时间相关
  111. // WORD Data3 // 和时间相关
  112. // BYTE Data4[8] // 和网卡 MAC 相关
  113. var guid = new byte[16];
  114. // 全部生成随机数。
  115. for (var i = 0; i < 16; i++) guid[i] = Convert.ToByte(NumberUtility.Random(255, 0));
  116. guid[6] &= 0x0f;
  117. guid[6] |= 0x04;
  118. guid[7] &= 0xff;
  119. guid[7] |= 0x00;
  120. guid[8] &= 0x3f;
  121. guid[8] |= 0x80;
  122. return guid;
  123. }
  124. #endregion
  125. #region Restrict 约束值范围。
  126. /// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
  127. public static T Restrict<T>(T origin, T min, T max) where T : IComparable
  128. {
  129. try
  130. {
  131. // 检查条件 min > max : 返回原始值。
  132. var condition = min.CompareTo(max);
  133. if (condition > 0) return origin;
  134. if (origin.CompareTo(min) < 0) return min;
  135. if (origin.CompareTo(max) > 0) return max;
  136. return origin;
  137. }
  138. catch { }
  139. return origin;
  140. }
  141. #endregion
  142. /// <summary>平均值。</summary>
  143. public static double Average(params double[] values)
  144. {
  145. var amount = 0d;
  146. foreach (var i in values) amount += i;
  147. return amount / Convert.ToDouble(values.Length);
  148. }
  149. #region 最小值、最大值。
  150. private static T GetMost<T>(Func<T, T, bool> replace, T[] values)
  151. {
  152. if (values == null) return default;
  153. var length = values.LongLength;
  154. if (length == 0L) return default;
  155. if (length == 1L) return values[0L];
  156. var most = values[0];
  157. for (var i = 1L; i < length; i++)
  158. {
  159. var value = values[i];
  160. if (value == null) continue;
  161. if (most == null)
  162. {
  163. most = value;
  164. }
  165. else
  166. {
  167. var doReplace = replace(most, value);
  168. if (doReplace) most = value;
  169. }
  170. }
  171. return most;
  172. }
  173. // 无法输出正确结果。
  174. // public static T GetMin<T>(params IComparable[] values)
  175. // {
  176. // var result = GetMost((a, b) => a.CompareTo(b) == 1, values);
  177. // return result == null ? default : (T)result;
  178. // }
  179. // 无法输出正确结果。
  180. // public static T GetMin<T>(params IComparable<T>[] values)
  181. // {
  182. // var result = GetMost((a, b) => a.CompareTo((T)b) == 1, values);
  183. // return result == null ? default : (T)result;
  184. // }
  185. // 无法输出正确结果。
  186. // public static T GetMax<T>(params IComparable[] values)
  187. // {
  188. // var result = GetMost((a, b) => a.CompareTo(b) == -1, values);
  189. // return result == null ? default : (T)result;
  190. // }
  191. // 无法输出正确结果。
  192. // public static T GetMax<T>(params IComparable<T>[] values)
  193. // {
  194. // var result = GetMost((a, b) => a.CompareTo((T)b) == -1, values);
  195. // return result == null ? default : (T)result;
  196. // }
  197. /// <summary>最小值。</summary>
  198. public static byte Min(params byte[] values) => GetMost((a, b) => a > b, values);
  199. /// <summary>最小值。</summary>
  200. public static int Min(params int[] values) => GetMost((a, b) => a > b, values);
  201. /// <summary>最小值。</summary>
  202. public static long Min(params long[] values) => GetMost((a, b) => a > b, values);
  203. /// <summary>最小值。</summary>
  204. public static float Min(params float[] values) => GetMost((a, b) => a > b, values);
  205. /// <summary>最小值。</summary>
  206. public static double Min(params double[] values) => GetMost((a, b) => a > b, values);
  207. /// <summary>最小值。</summary>
  208. public static decimal Min(params decimal[] values) => GetMost((a, b) => a > b, values);
  209. /// <summary>最大值。</summary>
  210. public static byte Max(params byte[] values) => GetMost((a, b) => a < b, values);
  211. /// <summary>最大值。</summary>
  212. public static int Max(params int[] values) => GetMost((a, b) => a < b, values);
  213. /// <summary>最大值。</summary>
  214. public static long Max(params long[] values) => GetMost((a, b) => a < b, values);
  215. /// <summary>最大值。</summary>
  216. public static float Max(params float[] values) => GetMost((a, b) => a < b, values);
  217. /// <summary>最大值。</summary>
  218. public static double Max(params double[] values) => GetMost((a, b) => a < b, values);
  219. /// <summary>最大值。</summary>
  220. public static decimal Max(params decimal[] values) => GetMost((a, b) => a < b, values);
  221. #endregion
  222. /// <summary>Pearson Correlation Coefficient 皮尔逊相关系数。计算两个数组的相似度。数组长度不相等时,以 0 填充不足的长度。</summary>
  223. /// <remarks>
  224. /// <para>0.8 ~ 1.0 : 极强相关</para>
  225. /// <para>0.6 ~ 0.8 : 强相关</para>
  226. /// <para>0.4 ~ 0.6 : 中等程度相关</para>
  227. /// <para>0.2 ~ 0.4 : 弱相关</para>
  228. /// <para>0.0 ~ 0.2 : 极弱相关或无相关</para>
  229. /// </remarks>
  230. /// <exception cref="ArgumentException"></exception>
  231. public static double Pearson(double[] bytes1, double[] bytes2)
  232. {
  233. var length1 = bytes1 == null ? 0L : bytes1.LongLength;
  234. var length2 = bytes2 == null ? 0L : bytes2.LongLength;
  235. var length = Math.Max(length1, length2);
  236. if (length < 1) return 1D;
  237. var x = new double[length];
  238. var y = new double[length];
  239. for (var i = 0L; i < length; i++)
  240. {
  241. if (i < length1) x[i] = bytes1[i];
  242. if (i < length2) y[i] = bytes2[i];
  243. }
  244. int n = x.Length; // 数组长度。
  245. double s = 0d; // 分子。
  246. double m1 = 0d, m2 = 0d; // 分母。
  247. double xa = Average(x);
  248. double ya = Average(y);
  249. for (int i = 0; i < n; i++)
  250. {
  251. s += (x[i] - xa) * (y[i] - ya);
  252. m1 += Math.Pow(x[i] - xa, 2);
  253. m2 += Math.Pow(y[i] - ya, 2);
  254. }
  255. double r = s / (Math.Sqrt(m1) * Math.Sqrt(m2));
  256. return r;
  257. }
  258. #region 从 String 转为数值。
  259. // 修剪数值字符串。
  260. private static string Trim(string text)
  261. {
  262. if (string.IsNullOrEmpty(text)) return null;
  263. const string allowed = "0123456789.%+-Ee。";
  264. var input = text.Length;
  265. var output = 0;
  266. var chars = new char[input];
  267. for (var i = 0; i < text.Length; i++)
  268. {
  269. var c = text[i];
  270. if (c == '。') c = '.';
  271. else if (allowed.IndexOf(c) < 0) continue;
  272. chars[output] = c;
  273. output += 1;
  274. }
  275. if (output == input) return text;
  276. if (output < 1) return null;
  277. return new string(chars, 0, output);
  278. }
  279. private static T GetNumber<T>(object @object, Func<string, T> convert, Func<T, double, T> percent = null)
  280. {
  281. if (@object == null) return default(T);
  282. if (@object is T) return (T)@object;
  283. var text = (@object is string) ? (string)@object : @object.ToString();
  284. var trim = Trim(text);
  285. if (trim == null) return default;
  286. // 获取百分号的个数。
  287. var pow = 0;
  288. while (trim.Length > 0 && trim.EndsWith("%"))
  289. {
  290. trim = trim.Substring(0, trim.Length - 1);
  291. pow += 1;
  292. }
  293. if (trim.Length < 1) return default;
  294. // 转换。
  295. try
  296. {
  297. var value = convert(trim);
  298. if (pow > 0 && percent != null)
  299. {
  300. var denominator = Math.Pow(100, pow);
  301. value = percent(value, denominator);
  302. }
  303. return value;
  304. }
  305. catch { return default; }
  306. }
  307. private static decimal DecimalAsFloat(string text)
  308. {
  309. try { return Convert.ToDecimal(text); } catch { }
  310. try { return decimal.Parse(text, NumberStyles.Float); } catch { }
  311. return default(decimal);
  312. }
  313. /// <summary>获取布尔对象。</summary>
  314. public static bool Boolean(object any)
  315. {
  316. if (any.IsNull()) return false;
  317. if (any is bool _bool) return _bool;
  318. if (any is byte _byte) return _byte == 1;
  319. if (any is sbyte _sbyte) return _sbyte == 1;
  320. if (any is short _short) return _short == 1;
  321. if (any is ushort _ushort) return _ushort == 1;
  322. if (any is int _int) return _int == 1;
  323. if (any is uint _uint) return _uint == 1;
  324. if (any is long _long) return _long == 1;
  325. if (any is ulong _ulong) return _ulong == 1;
  326. if (any is float _float) return _float == 1;
  327. if (any is double _double) return _double == 1;
  328. if (any is decimal _decimal) return _decimal == 1;
  329. if (any is string _string)
  330. {
  331. var lower = TextUtility.Lower(_string);
  332. if (lower == "true" || lower == "yes" || lower == "y" || lower == "1") return true;
  333. }
  334. return false;
  335. }
  336. /// <summary>获取单精度浮点对象。</summary>
  337. public static float Float(object number) => GetNumber(number, Convert.ToSingle, (v, d) => v / Convert.ToSingle(d));
  338. /// <summary>获取单精度浮点对象。</summary>
  339. public static float Single(object number) => GetNumber(number, Convert.ToSingle, (v, d) => v / Convert.ToSingle(d));
  340. /// <summary>获取双精度浮点对象。</summary>
  341. public static double Double(object number) => GetNumber(number, Convert.ToDouble, (v, d) => v / d);
  342. /// <summary>获取 Decimal 对象。</summary>
  343. public static decimal Decimal(object number) => GetNumber(number, DecimalAsFloat, (v, d) => v / Convert.ToDecimal(d));
  344. /// <summary>获取 Byte 对象。</summary>
  345. public static byte Byte(object number) => GetNumber(number, Convert.ToByte);
  346. /// <summary>获取 SByte 对象。</summary>
  347. public static sbyte SByte(object number) => GetNumber(number, Convert.ToSByte);
  348. /// <summary>获取 Int16 对象。</summary>
  349. public static short Int16(object number) => GetNumber(number, Convert.ToInt16);
  350. /// <summary>获取 UInt16 对象。</summary>
  351. public static ushort UInt16(object number) => GetNumber(number, Convert.ToUInt16);
  352. /// <summary>获取 Int32 对象。</summary>
  353. public static int Int32(object number) => GetNumber(number, Convert.ToInt32);
  354. /// <summary>获取 UInt32 对象。</summary>
  355. public static uint UInt32(object number) => GetNumber(number, Convert.ToUInt32);
  356. /// <summary>获取 Int64 对象。</summary>
  357. public static long Int64(object number) => GetNumber(number, Convert.ToInt64);
  358. /// <summary>获取 UInt64 对象。</summary>
  359. public static ulong UInt64(object number) => GetNumber(number, Convert.ToUInt64);
  360. #endregion
  361. }
  362. }