本博客所有文章分类的总目录:【总目录】本博客博文总目录-实时更新
开源Math.NET基础数学类库使用总目录:【目录】开源Math.NET基础数学类库使用总目录
前言
数论就是指研究整数性质的一门理论。数论=算术。不过通常算术指数的计算,数论指数的理论。整数的基本元素是素数,所以数论的本质是对素数性质的研究。它是与平面几何同样历史悠久的学科。它大致包括代数数论、解析数论、计算数论等等。
Math.NET也包括了很多数论相关的函数,这些函数都是静态的,可以直接调用,如判断是否奇数,判断幂,平方数,最大公约数等等。同时部分函数已经作为扩展方法,可以直接在对象中使用。
如果本文资源或者显示有问题,请参考 本文原文地址:http://www.cnblogs.com/asxinyu/p/4301097.html
1.数论函数类Euclid
Math.NET包括的数论函数除了一部分大家日常接触到的,奇数,偶数,幂,平方数,最大公约数,最小公倍数等函数,还有一些欧几里得几何的函数,当然也是比较简单的,这些问题的算法有一些比较简单,如最大公约数,最小公倍数等,都有成熟的算法可以使用,对于使用Math.NET的人来说,不必要了解太小,当然对于需要搞清楚原理的人来说,学习Math.NET的架构或者实现,是可以参考的。所以这里先给出Math.NET关于数论函数类Euclid的源代码:
1 /// <summary> 2 /// 整数数论函数 3 /// Integer number theory functions. 4 /// </summary> 5 public static class Euclid 6 { 7 /// <summary> 8 /// Canonical Modulus. The result has the sign of the divisor. 9 /// </summary> 10 public static double Modulus(double dividend, double divisor) 11 { 12 return ((dividend%divisor) + divisor)%divisor; 13 } 14 15 /// <summary> 16 /// Canonical Modulus. The result has the sign of the divisor. 17 /// </summary> 18 public static float Modulus(float dividend, float divisor) 19 { 20 return ((dividend%divisor) + divisor)%divisor; 21 } 22 23 /// <summary> 24 /// Canonical Modulus. The result has the sign of the divisor. 25 /// </summary> 26 public static int Modulus(int dividend, int divisor) 27 { 28 return ((dividend%divisor) + divisor)%divisor; 29 } 30 31 /// <summary> 32 /// Canonical Modulus. The result has the sign of the divisor. 33 /// </summary> 34 public static long Modulus(long dividend, long divisor) 35 { 36 return ((dividend%divisor) + divisor)%divisor; 37 } 38 39 #if !NOSYSNUMERICS 40 /// <summary> 41 /// Canonical Modulus. The result has the sign of the divisor. 42 /// </summary> 43 public static BigInteger Modulus(BigInteger dividend, BigInteger divisor) 44 { 45 return ((dividend%divisor) + divisor)%divisor; 46 } 47 #endif 48 49 /// <summary> 50 /// Remainder (% operator). The result has the sign of the dividend. 51 /// </summary> 52 public static double Remainder(double dividend, double divisor) 53 { 54 return dividend%divisor; 55 } 56 57 /// <summary> 58 /// Remainder (% operator). The result has the sign of the dividend. 59 /// </summary> 60 public static float Remainder(float dividend, float divisor) 61 { 62 return dividend%divisor; 63 } 64 65 /// <summary> 66 /// Remainder (% operator). The result has the sign of the dividend. 67 /// </summary> 68 public static int Remainder(int dividend, int divisor) 69 { 70 return dividend%divisor; 71 } 72 73 /// <summary> 74 /// Remainder (% operator). The result has the sign of the dividend. 75 /// </summary> 76 public static long Remainder(long dividend, long divisor) 77 { 78 return dividend%divisor; 79 } 80 81 #if !NOSYSNUMERICS 82 /// <summary> 83 /// Remainder (% operator). The result has the sign of the dividend. 84 /// </summary> 85 public static BigInteger Remainder(BigInteger dividend, BigInteger divisor) 86 { 87 return dividend%divisor; 88 } 89 #endif 90 91 /// <summary> 92 /// Find out whether the provided 32 bit integer is an even number. 93 /// </summary> 94 /// <param name="number">The number to very whether it's even.</param> 95 /// <returns>True if and only if it is an even number.</returns> 96 public static bool IsEven(this int number) 97 { 98 return (number & 0x1) == 0x0; 99 } 100 101 /// <summary> 102 /// Find out whether the provided 64 bit integer is an even number. 103 /// </summary> 104 /// <param name="number">The number to very whether it's even.</param> 105 /// <returns>True if and only if it is an even number.</returns> 106 public static bool IsEven(this long number) 107 { 108 return (number & 0x1) == 0x0; 109 } 110 111 /// <summary> 112 /// Find out whether the provided 32 bit integer is an odd number. 113 /// </summary> 114 /// <param name="number">The number to very whether it's odd.</param> 115 /// <returns>True if and only if it is an odd number.</returns> 116 public static bool IsOdd(this int number) 117 { 118 return (number & 0x1) == 0x1; 119 } 120 121 /// <summary> 122 /// Find out whether the provided 64 bit integer is an odd number. 123 /// </summary> 124 /// <param name="number">The number to very whether it's odd.</param> 125 /// <returns>True if and only if it is an odd number.</returns> 126 public static bool IsOdd(this long number) 127 { 128 return (number & 0x1) == 0x1; 129 } 130 131 /// <summary> 132 /// Find out whether the provided 32 bit integer is a perfect power of two. 133 /// </summary> 134 /// <param name="number">The number to very whether it's a power of two.</param> 135 /// <returns>True if and only if it is a power of two.</returns> 136 public static bool IsPowerOfTwo(this int number) 137 { 138 return number > 0 && (number & (number - 1)) == 0x0; 139 } 140 141 /// <summary> 142 /// Find out whether the provided 64 bit integer is a perfect power of two. 143 /// </summary> 144 /// <param name="number">The number to very whether it's a power of two.</param> 145 /// <returns>True if and only if it is a power of two.</returns> 146 public static bool IsPowerOfTwo(this long number) 147 { 148 return number > 0 && (number & (number - 1)) == 0x0; 149 } 150 151 /// <summary> 152 /// Find out whether the provided 32 bit integer is a perfect square, i.e. a square of an integer. 153 /// </summary> 154 /// <param name="number">The number to very whether it's a perfect square.</param> 155 /// <returns>True if and only if it is a perfect square.</returns> 156 public static bool IsPerfectSquare(this int number) 157 { 158 if (number < 0) 159 { 160 return false; 161 } 162 163 int lastHexDigit = number & 0xF; 164 if (lastHexDigit > 9) 165 { 166 return false; // return immediately in 6 cases out of 16. 167 } 168 169 if (lastHexDigit == 0 || lastHexDigit == 1 || lastHexDigit == 4 || lastHexDigit == 9) 170 { 171 int t = (int)Math.Floor(Math.Sqrt(number) + 0.5); 172 return (t * t) == number; 173 } 174 175 return false; 176 } 177 178 /// <summary> 179 /// Find out whether the provided 64 bit integer is a perfect square, i.e. a square of an integer. 180 /// </summary> 181 /// <param name="number">The number to very whether it's a perfect square.</param> 182 /// <returns>True if and only if it is a perfect square.</returns> 183 public static bool IsPerfectSquare(this long number) 184 { 185 if (number < 0) 186 { 187 return false; 188 } 189 190 int lastHexDigit = (int)(number & 0xF); 191 if (lastHexDigit > 9) 192 { 193 return false; // return immediately in 6 cases out of 16. 194 } 195 196 if (lastHexDigit == 0 || lastHexDigit == 1 || lastHexDigit == 4 || lastHexDigit == 9) 197 { 198 long t = (long)Math.Floor(Math.Sqrt(number) + 0.5); 199 return (t * t) == number; 200 } 201 202 return false; 203 } 204 205 /// <summary> 206 /// Raises 2 to the provided integer exponent (0 <= exponent < 31). 207 /// </summary> 208 /// <param name="exponent">The exponent to raise 2 up to.</param> 209 /// <returns>2 ^ exponent.</returns> 210 /// <exception cref="ArgumentOutOfRangeException"/> 211 public static int PowerOfTwo(this int exponent) 212 { 213 if (exponent < 0 || exponent >= 31) 214 { 215 throw new ArgumentOutOfRangeException("exponent"); 216 } 217 218 return 1 << exponent; 219 } 220 221 /// <summary> 222 /// Raises 2 to the provided integer exponent (0 <= exponent < 63). 223 /// </summary> 224 /// <param name="exponent">The exponent to raise 2 up to.</param> 225 /// <returns>2 ^ exponent.</returns> 226 /// <exception cref="ArgumentOutOfRangeException"/> 227 public static long PowerOfTwo(this long exponent) 228 { 229 if (exponent < 0 || exponent >= 63) 230 { 231 throw new ArgumentOutOfRangeException("exponent"); 232 } 233 234 return ((long)1) << (int)exponent; 235 } 236 237 /// <summary> 238 /// Find the closest perfect power of two that is larger or equal to the provided 239 /// 32 bit integer. 240 /// </summary> 241 /// <param name="number">The number of which to find the closest upper power of two.</param> 242 /// <returns>A power of two.</returns> 243 /// <exception cref="ArgumentOutOfRangeException"/> 244 public static int CeilingToPowerOfTwo(this int number) 245 { 246 if (number == Int32.MinValue) 247 { 248 return 0; 249 } 250 251 const int maxPowerOfTwo = 0x40000000; 252 if (number > maxPowerOfTwo) 253 { 254 throw new ArgumentOutOfRangeException("number"); 255 } 256 257 number--; 258 number |= number >> 1; 259 number |= number >> 2; 260 number |= number >> 4; 261 number |= number >> 8; 262 number |= number >> 16; 263 return number + 1; 264 } 265 266 /// <summary> 267 /// Find the closest perfect power of two that is larger or equal to the provided 268 /// 64 bit integer. 269 /// </summary> 270 /// <param name="number">The number of which to find the closest upper power of two.</param> 271 /// <returns>A power of two.</returns> 272 /// <exception cref="ArgumentOutOfRangeException"/> 273 public static long CeilingToPowerOfTwo(this long number) 274 { 275 if (number == Int64.MinValue) 276 { 277 return 0; 278 } 279 280 const long maxPowerOfTwo = 0x4000000000000000; 281 if (number > maxPowerOfTwo) 282 { 283 throw new ArgumentOutOfRangeException("number"); 284 } 285 286 number--; 287 number |= number >> 1; 288 number |= number >> 2; 289 number |= number >> 4; 290 number |= number >> 8; 291 number |= number >> 16; 292 number |= number >> 32; 293 return number + 1; 294 } 295 296 /// <summary> 297 /// Returns the greatest common divisor (<c>gcd</c>) of two integers using Euclid's algorithm. 298 /// </summary> 299 /// <param name="a">First Integer: a.</param> 300 /// <param name="b">Second Integer: b.</param> 301 /// <returns>Greatest common divisor <c>gcd</c>(a,b)</returns> 302 public static long GreatestCommonDivisor(long a, long b) 303 { 304 while (b != 0) 305 { 306 var remainder = a%b; 307 a = b; 308 b = remainder; 309 } 310 311 return Math.Abs(a); 312 } 313 314 /// <summary> 315 /// Returns the greatest common divisor (<c>gcd</c>) of a set of integers using Euclid's 316 /// algorithm. 317 /// </summary> 318 /// <param name="integers">List of Integers.</param> 319 /// <returns>Greatest common divisor <c>gcd</c>(list of integers)</returns> 320 public static long GreatestCommonDivisor(IList<long> integers) 321 { 322 if (null == integers) 323 { 324 throw new ArgumentNullException("integers"); 325 } 326 327 if (integers.Count == 0) 328 { 329 return 0; 330 } 331 332 var gcd = Math.Abs(integers[0]); 333 334 for (var i = 1; (i < integers.Count) && (gcd > 1); i++) 335 { 336 gcd = GreatestCommonDivisor(gcd, integers[i]); 337 } 338 339 return gcd; 340 } 341 342 /// <summary> 343 /// Returns the greatest common divisor (<c>gcd</c>) of a set of integers using Euclid's algorithm. 344 /// </summary> 345 /// <param name="integers">List of Integers.</param> 346 /// <returns>Greatest common divisor <c>gcd</c>(list of integers)</returns> 347 public static long GreatestCommonDivisor(params long[] integers) 348 { 349 return GreatestCommonDivisor((IList<long>)integers); 350 } 351 352 /// <summary> 353 /// Computes the extended greatest common divisor, such that a*x + b*y = <c>gcd</c>(a,b). 354 /// </summary> 355 /// <param name="a">First Integer: a.</param> 356 /// <param name="b">Second Integer: b.</param> 357 /// <param name="x">Resulting x, such that a*x + b*y = <c>gcd</c>(a,b).</param> 358 /// <param name="y">Resulting y, such that a*x + b*y = <c>gcd</c>(a,b)</param> 359 /// <returns>Greatest common divisor <c>gcd</c>(a,b)</returns> 360 /// <example> 361 /// <code> 362 /// long x,y,d; 363 /// d = Fn.GreatestCommonDivisor(45,18,out x, out y); 364 /// -> d == 9 && x == 1 && y == -2 365 /// </code> 366 /// The <c>gcd</c> of 45 and 18 is 9: 18 = 2*9, 45 = 5*9. 9 = 1*45 -2*18, therefore x=1 and y=-2. 367 /// </example> 368 public static long ExtendedGreatestCommonDivisor(long a, long b, out long x, out long y) 369 { 370 long mp = 1, np = 0, m = 0, n = 1; 371 372 while (b != 0) 373 { 374 long rem; 375 #if PORTABLE 376 rem = a % b; 377 var quot = a / b; 378 #else 379 long quot = Math.DivRem(a, b, out rem); 380 #endif 381 a = b; 382 b = rem; 383 384 var tmp = m; 385 m = mp - (quot*m); 386 mp = tmp; 387 388 tmp = n; 389 n = np - (quot*n); 390 np = tmp; 391 } 392 393 if (a >= 0) 394 { 395 x = mp; 396 y = np; 397 return a; 398 } 399 400 x = -mp; 401 y = -np; 402 return -a; 403 } 404 405 /// <summary> 406 /// Returns the least common multiple (<c>lcm</c>) of two integers using Euclid's algorithm. 407 /// </summary> 408 /// <param name="a">First Integer: a.</param> 409 /// <param name="b">Second Integer: b.</param> 410 /// <returns>Least common multiple <c>lcm</c>(a,b)</returns> 411 public static long LeastCommonMultiple(long a, long b) 412 { 413 if ((a == 0) || (b == 0)) 414 { 415 return 0; 416 } 417 418 return Math.Abs((a/GreatestCommonDivisor(a, b))*b); 419 } 420 421 /// <summary> 422 /// Returns the least common multiple (<c>lcm</c>) of a set of integers using Euclid's algorithm. 423 /// </summary> 424 /// <param name="integers">List of Integers.</param> 425 /// <returns>Least common multiple <c>lcm</c>(list of integers)</returns> 426 public static long LeastCommonMultiple(IList<long> integers) 427 { 428 if (null == integers) 429 { 430 throw new ArgumentNullException("integers"); 431 } 432 433 if (integers.Count == 0) 434 { 435 return 1; 436 } 437 438 var lcm = Math.Abs(integers[0]); 439 440 for (var i = 1; i < integers.Count; i++) 441 { 442 lcm = LeastCommonMultiple(lcm, integers[i]); 443 } 444 445 return lcm; 446 } 447 448 /// <summary> 449 /// Returns the least common multiple (<c>lcm</c>) of a set of integers using Euclid's algorithm. 450 /// </summary> 451 /// <param name="integers">List of Integers.</param> 452 /// <returns>Least common multiple <c>lcm</c>(list of integers)</returns> 453 public static long LeastCommonMultiple(params long[] integers) 454 { 455 return LeastCommonMultiple((IList<long>)integers); 456 } 457 458 #if !NOSYSNUMERICS 459 /// <summary> 460 /// Returns the greatest common divisor (<c>gcd</c>) of two big integers. 461 /// </summary> 462 /// <param name="a">First Integer: a.</param> 463 /// <param name="b">Second Integer: b.</param> 464 /// <returns>Greatest common divisor <c>gcd</c>(a,b)</returns> 465 public static BigInteger GreatestCommonDivisor(BigInteger a, BigInteger b) 466 { 467 return BigInteger.GreatestCommonDivisor(a, b); 468 } 469 470 /// <summary> 471 /// Returns the greatest common divisor (<c>gcd</c>) of a set of big integers. 472 /// </summary> 473 /// <param name="integers">List of Integers.</param> 474 /// <returns>Greatest common divisor <c>gcd</c>(list of integers)</returns> 475 public static BigInteger GreatestCommonDivisor(IList<BigInteger> integers) 476 { 477 if (null == integers) 478 { 479 throw new ArgumentNullException("integers"); 480 } 481 482 if (integers.Count == 0) 483 { 484 return 0; 485 } 486 487 var gcd = BigInteger.Abs(integers[0]); 488 489 for (int i = 1; (i < integers.Count) && (gcd > BigInteger.One); i++) 490 { 491 gcd = GreatestCommonDivisor(gcd, integers[i]); 492 } 493 494 return gcd; 495 } 496 497 /// <summary> 498 /// Returns the greatest common divisor (<c>gcd</c>) of a set of big integers. 499 /// </summary> 500 /// <param name="integers">List of Integers.</param> 501 /// <returns>Greatest common divisor <c>gcd</c>(list of integers)</returns> 502 public static BigInteger GreatestCommonDivisor(params BigInteger[] integers) 503 { 504 return GreatestCommonDivisor((IList<BigInteger>)integers); 505 } 506 507 /// <summary> 508 /// Computes the extended greatest common divisor, such that a*x + b*y = <c>gcd</c>(a,b). 509 /// </summary> 510 /// <param name="a">First Integer: a.</param> 511 /// <param name="b">Second Integer: b.</param> 512 /// <param name="x">Resulting x, such that a*x + b*y = <c>gcd</c>(a,b).</param> 513 /// <param name="y">Resulting y, such that a*x + b*y = <c>gcd</c>(a,b)</param> 514 /// <returns>Greatest common divisor <c>gcd</c>(a,b)</returns> 515 /// <example> 516 /// <code> 517 /// long x,y,d; 518 /// d = Fn.GreatestCommonDivisor(45,18,out x, out y); 519 /// -> d == 9 && x == 1 && y == -2 520 /// </code> 521 /// The <c>gcd</c> of 45 and 18 is 9: 18 = 2*9, 45 = 5*9. 9 = 1*45 -2*18, therefore x=1 and y=-2. 522 /// </example> 523 public static BigInteger ExtendedGreatestCommonDivisor(BigInteger a, BigInteger b, out BigInteger x, out BigInteger y) 524 { 525 BigInteger mp = BigInteger.One, np = BigInteger.Zero, m = BigInteger.Zero, n = BigInteger.One; 526 527 while (!b.IsZero) 528 { 529 BigInteger rem; 530 BigInteger quot = BigInteger.DivRem(a, b, out rem); 531 a = b; 532 b = rem; 533 534 BigInteger tmp = m; 535 m = mp - (quot*m); 536 mp = tmp; 537 538 tmp = n; 539 n = np - (quot*n); 540 np = tmp; 541 } 542 543 if (a >= BigInteger.Zero) 544 { 545 x = mp; 546 y = np; 547 return a; 548 } 549 550 x = -mp; 551 y = -np; 552 return -a; 553 } 554 555 /// <summary> 556 /// Returns the least common multiple (<c>lcm</c>) of two big integers. 557 /// </summary> 558 /// <param name="a">First Integer: a.</param> 559 /// <param name="b">Second Integer: b.</param> 560 /// <returns>Least common multiple <c>lcm</c>(a,b)</returns> 561 public static BigInteger LeastCommonMultiple(BigInteger a, BigInteger b) 562 { 563 if (a.IsZero || b.IsZero) 564 { 565 return BigInteger.Zero; 566 } 567 568 return BigInteger.Abs((a/BigInteger.GreatestCommonDivisor(a, b))*b); 569 } 570 571 /// <summary> 572 /// Returns the least common multiple (<c>lcm</c>) of a set of big integers. 573 /// </summary> 574 /// <param name="integers">List of Integers.</param> 575 /// <returns>Least common multiple <c>lcm</c>(list of integers)</returns> 576 public static BigInteger LeastCommonMultiple(IList<BigInteger> integers) 577 { 578 if (null == integers) 579 { 580 throw new ArgumentNullException("integers"); 581 } 582 583 if (integers.Count == 0) 584 { 585 return 1; 586 } 587 588 var lcm = BigInteger.Abs(integers[0]); 589 590 for (int i = 1; i < integers.Count; i++) 591 { 592 lcm = LeastCommonMultiple(lcm, integers[i]); 593 } 594 595 return lcm; 596 } 597 598 /// <summary> 599 /// Returns the least common multiple (<c>lcm</c>) of a set of big integers. 600 /// </summary> 601 /// <param name="integers">List of Integers.</param> 602 /// <returns>Least common multiple <c>lcm</c>(list of integers)</returns> 603 public static BigInteger LeastCommonMultiple(params BigInteger[] integers) 604 { 605 return LeastCommonMultiple((IList<BigInteger>)integers); 606 } 607 #endif 608 }
2.Euclid类的使用例子
上面已经看到源码,也提到了,Euclid作为静态类,其中的很多静态方法都可以直接作为扩展方法使用。这里看看几个简单的例子:
1 // 1. Find out whether the provided number is an even number 2 Console.WriteLine(@"1.判断提供的数字是否是偶数"); 3 Console.WriteLine(@"{0} 是偶数 = {1}. {2} 是偶数 = {3}", 1, Euclid.IsEven(1), 2, 2.IsEven()); 4 Console.WriteLine(); 5 6 // 2. Find out whether the provided number is an odd number 7 Console.WriteLine(@"2.判断提供的数字是否是奇数"); 8 Console.WriteLine(@"{0} 是奇数 = {1}. {2} 是奇数 = {3}", 1, 1.IsOdd(), 2, Euclid.IsOdd(2)); 9 Console.WriteLine(); 10 11 // 3. Find out whether the provided number is a perfect power of two 12 Console.WriteLine(@"2.判断提供的数字是否是2的幂"); 13 Console.WriteLine(@"{0} 是2的幂 = {1}. {2} 是2的幂 = {3}", 5, 5.IsPowerOfTwo(), 16, Euclid.IsPowerOfTwo(16)); 14 Console.WriteLine(); 15 16 // 4. Find the closest perfect power of two that is larger or equal to 97 17 Console.WriteLine(@"4.返回大于等于97的最小2的幂整数"); 18 Console.WriteLine(97.CeilingToPowerOfTwo()); 19 Console.WriteLine(); 20 21 // 5. Raise 2 to the 16 22 Console.WriteLine(@"5. 2的16次幂"); 23 Console.WriteLine(16.PowerOfTwo()); 24 Console.WriteLine(); 25 26 // 6. Find out whether the number is a perfect square 27 Console.WriteLine(@"6. 判断提供的数字是否是平方数"); 28 Console.WriteLine(@"{0} 是平方数 = {1}. {2} 是平方数 = {3}", 37, 37.IsPerfectSquare(), 81, Euclid.IsPerfectSquare(81)); 29 Console.WriteLine(); 30 31 // 7. Compute the greatest common divisor of 32 and 36 32 Console.WriteLine(@"7. 返回32和36的最大公约数"); 33 Console.WriteLine(Euclid.GreatestCommonDivisor(32, 36)); 34 Console.WriteLine(); 35 36 // 8. Compute the greatest common divisor of 492, -984, 123, 246 37 Console.WriteLine(@"8. 返回的最大公约数:492、-984、123、246"); 38 Console.WriteLine(Euclid.GreatestCommonDivisor(492, -984, 123, 246)); 39 Console.WriteLine(); 40 41 // 9. Compute the least common multiple of 16 and 12 42 Console.WriteLine(@"10. 计算的最小公倍数:16和12"); 43 Console.WriteLine(Euclid.LeastCommonMultiple(16, 12)); 44 Console.WriteLine();
结果如下:
1.判断提供的数字是否是偶数 1 是偶数 = False. 2 是偶数 = True 2.判断提供的数字是否是奇数 1 是奇数 = True. 2 是奇数 = False 2.判断提供的数字是否是2的幂 5 是2的幂 = False. 16 是2的幂 = True 4.返回大于等于97的最小2的幂整数 128 5. 2的16次幂 65536 6. 判断提供的数字是否是平方数 37 是平方数 = False. 81 是平方数 = True 7. 返回32和36的最大公约数 4 8. 返回的最大公约数:492、-984、123、246 123 10. 计算的最小公倍数:16和12 48
3.资源
源码下载:http://www.cnblogs.com/asxinyu/p/4264638.html
如果本文资源或者显示有问题,请参考 本文原文地址:http://www.cnblogs.com/asxinyu/p/4301097.html