Math.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. /*============================================================
  5. **
  6. **
  7. **
  8. ** Purpose: Some floating-point math operations
  9. **
  10. **
  11. ===========================================================*/
  12. //This class contains only static members and doesn't require serialization.
  13. using System.Diagnostics;
  14. using System.Diagnostics.CodeAnalysis;
  15. using System.Runtime;
  16. using System.Runtime.CompilerServices;
  17. using System.Runtime.Versioning;
  18. namespace System
  19. {
  20. public static partial class Math
  21. {
  22. public const double E = 2.7182818284590452354;
  23. public const double PI = 3.14159265358979323846;
  24. private const int maxRoundingDigits = 15;
  25. private const double doubleRoundLimit = 1e16d;
  26. // This table is required for the Round function which can specify the number of digits to round to
  27. private static double[] roundPower10Double = new double[] {
  28. 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
  29. 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15
  30. };
  31. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  32. public static short Abs(short value)
  33. {
  34. if (value < 0)
  35. {
  36. value = (short)-value;
  37. if (value < 0)
  38. {
  39. ThrowAbsOverflow();
  40. }
  41. }
  42. return value;
  43. }
  44. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  45. public static int Abs(int value)
  46. {
  47. if (value < 0)
  48. {
  49. value = -value;
  50. if (value < 0)
  51. {
  52. ThrowAbsOverflow();
  53. }
  54. }
  55. return value;
  56. }
  57. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  58. public static long Abs(long value)
  59. {
  60. if (value < 0)
  61. {
  62. value = -value;
  63. if (value < 0)
  64. {
  65. ThrowAbsOverflow();
  66. }
  67. }
  68. return value;
  69. }
  70. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  71. [CLSCompliant(false)]
  72. public static sbyte Abs(sbyte value)
  73. {
  74. if (value < 0)
  75. {
  76. value = (sbyte)-value;
  77. if (value < 0)
  78. {
  79. ThrowAbsOverflow();
  80. }
  81. }
  82. return value;
  83. }
  84. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  85. public static decimal Abs(decimal value)
  86. {
  87. return decimal.Abs(value);
  88. }
  89. [DoesNotReturn]
  90. [StackTraceHidden]
  91. private static void ThrowAbsOverflow()
  92. {
  93. throw new OverflowException(SR.Overflow_NegateTwosCompNum);
  94. }
  95. public static long BigMul(int a, int b)
  96. {
  97. return ((long)a) * b;
  98. }
  99. public static double BitDecrement(double x)
  100. {
  101. var bits = BitConverter.DoubleToInt64Bits(x);
  102. if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000)
  103. {
  104. // NaN returns NaN
  105. // -Infinity returns -Infinity
  106. // +Infinity returns double.MaxValue
  107. return (bits == 0x7FF00000_00000000) ? double.MaxValue : x;
  108. }
  109. if (bits == 0x00000000_00000000)
  110. {
  111. // +0.0 returns -double.Epsilon
  112. return -double.Epsilon;
  113. }
  114. // Negative values need to be incremented
  115. // Positive values need to be decremented
  116. bits += ((bits < 0) ? +1 : -1);
  117. return BitConverter.Int64BitsToDouble(bits);
  118. }
  119. public static double BitIncrement(double x)
  120. {
  121. var bits = BitConverter.DoubleToInt64Bits(x);
  122. if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000)
  123. {
  124. // NaN returns NaN
  125. // -Infinity returns double.MinValue
  126. // +Infinity returns +Infinity
  127. return (bits == unchecked((long)(0xFFF00000_00000000))) ? double.MinValue : x;
  128. }
  129. if (bits == unchecked((long)(0x80000000_00000000)))
  130. {
  131. // -0.0 returns double.Epsilon
  132. return double.Epsilon;
  133. }
  134. // Negative values need to be decremented
  135. // Positive values need to be incremented
  136. bits += ((bits < 0) ? -1 : +1);
  137. return BitConverter.Int64BitsToDouble(bits);
  138. }
  139. public static unsafe double CopySign(double x, double y)
  140. {
  141. // This method is required to work for all inputs,
  142. // including NaN, so we operate on the raw bits.
  143. var xbits = BitConverter.DoubleToInt64Bits(x);
  144. var ybits = BitConverter.DoubleToInt64Bits(y);
  145. // If the sign bits of x and y are not the same,
  146. // flip the sign bit of x and return the new value;
  147. // otherwise, just return x
  148. if ((xbits ^ ybits) < 0)
  149. {
  150. return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue);
  151. }
  152. return x;
  153. }
  154. public static int DivRem(int a, int b, out int result)
  155. {
  156. // TODO https://github.com/dotnet/coreclr/issues/3439:
  157. // Restore to using % and / when the JIT is able to eliminate one of the idivs.
  158. // In the meantime, a * and - is measurably faster than an extra /.
  159. int div = a / b;
  160. result = a - (div * b);
  161. return div;
  162. }
  163. public static long DivRem(long a, long b, out long result)
  164. {
  165. long div = a / b;
  166. result = a - (div * b);
  167. return div;
  168. }
  169. internal static uint DivRem(uint a, uint b, out uint result)
  170. {
  171. uint div = a / b;
  172. result = a - (div * b);
  173. return div;
  174. }
  175. internal static ulong DivRem(ulong a, ulong b, out ulong result)
  176. {
  177. ulong div = a / b;
  178. result = a - (div * b);
  179. return div;
  180. }
  181. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  182. public static decimal Ceiling(decimal d)
  183. {
  184. return decimal.Ceiling(d);
  185. }
  186. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  187. public static byte Clamp(byte value, byte min, byte max)
  188. {
  189. if (min > max)
  190. {
  191. ThrowMinMaxException(min, max);
  192. }
  193. if (value < min)
  194. {
  195. return min;
  196. }
  197. else if (value > max)
  198. {
  199. return max;
  200. }
  201. return value;
  202. }
  203. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  204. public static decimal Clamp(decimal value, decimal min, decimal max)
  205. {
  206. if (min > max)
  207. {
  208. ThrowMinMaxException(min, max);
  209. }
  210. if (value < min)
  211. {
  212. return min;
  213. }
  214. else if (value > max)
  215. {
  216. return max;
  217. }
  218. return value;
  219. }
  220. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  221. public static double Clamp(double value, double min, double max)
  222. {
  223. if (min > max)
  224. {
  225. ThrowMinMaxException(min, max);
  226. }
  227. if (value < min)
  228. {
  229. return min;
  230. }
  231. else if (value > max)
  232. {
  233. return max;
  234. }
  235. return value;
  236. }
  237. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  238. public static short Clamp(short value, short min, short max)
  239. {
  240. if (min > max)
  241. {
  242. ThrowMinMaxException(min, max);
  243. }
  244. if (value < min)
  245. {
  246. return min;
  247. }
  248. else if (value > max)
  249. {
  250. return max;
  251. }
  252. return value;
  253. }
  254. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  255. public static int Clamp(int value, int min, int max)
  256. {
  257. if (min > max)
  258. {
  259. ThrowMinMaxException(min, max);
  260. }
  261. if (value < min)
  262. {
  263. return min;
  264. }
  265. else if (value > max)
  266. {
  267. return max;
  268. }
  269. return value;
  270. }
  271. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  272. public static long Clamp(long value, long min, long max)
  273. {
  274. if (min > max)
  275. {
  276. ThrowMinMaxException(min, max);
  277. }
  278. if (value < min)
  279. {
  280. return min;
  281. }
  282. else if (value > max)
  283. {
  284. return max;
  285. }
  286. return value;
  287. }
  288. [CLSCompliant(false)]
  289. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  290. public static sbyte Clamp(sbyte value, sbyte min, sbyte max)
  291. {
  292. if (min > max)
  293. {
  294. ThrowMinMaxException(min, max);
  295. }
  296. if (value < min)
  297. {
  298. return min;
  299. }
  300. else if (value > max)
  301. {
  302. return max;
  303. }
  304. return value;
  305. }
  306. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  307. public static float Clamp(float value, float min, float max)
  308. {
  309. if (min > max)
  310. {
  311. ThrowMinMaxException(min, max);
  312. }
  313. if (value < min)
  314. {
  315. return min;
  316. }
  317. else if (value > max)
  318. {
  319. return max;
  320. }
  321. return value;
  322. }
  323. [CLSCompliant(false)]
  324. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  325. public static ushort Clamp(ushort value, ushort min, ushort max)
  326. {
  327. if (min > max)
  328. {
  329. ThrowMinMaxException(min, max);
  330. }
  331. if (value < min)
  332. {
  333. return min;
  334. }
  335. else if (value > max)
  336. {
  337. return max;
  338. }
  339. return value;
  340. }
  341. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  342. [CLSCompliant(false)]
  343. public static uint Clamp(uint value, uint min, uint max)
  344. {
  345. if (min > max)
  346. {
  347. ThrowMinMaxException(min, max);
  348. }
  349. if (value < min)
  350. {
  351. return min;
  352. }
  353. else if (value > max)
  354. {
  355. return max;
  356. }
  357. return value;
  358. }
  359. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  360. [CLSCompliant(false)]
  361. public static ulong Clamp(ulong value, ulong min, ulong max)
  362. {
  363. if (min > max)
  364. {
  365. ThrowMinMaxException(min, max);
  366. }
  367. if (value < min)
  368. {
  369. return min;
  370. }
  371. else if (value > max)
  372. {
  373. return max;
  374. }
  375. return value;
  376. }
  377. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  378. public static decimal Floor(decimal d)
  379. {
  380. return decimal.Floor(d);
  381. }
  382. public static double IEEERemainder(double x, double y)
  383. {
  384. if (double.IsNaN(x))
  385. {
  386. return x; // IEEE 754-2008: NaN payload must be preserved
  387. }
  388. if (double.IsNaN(y))
  389. {
  390. return y; // IEEE 754-2008: NaN payload must be preserved
  391. }
  392. var regularMod = x % y;
  393. if (double.IsNaN(regularMod))
  394. {
  395. return double.NaN;
  396. }
  397. if ((regularMod == 0) && double.IsNegative(x))
  398. {
  399. return double.NegativeZero;
  400. }
  401. var alternativeResult = (regularMod - (Abs(y) * Sign(x)));
  402. if (Abs(alternativeResult) == Abs(regularMod))
  403. {
  404. var divisionResult = x / y;
  405. var roundedResult = Round(divisionResult);
  406. if (Abs(roundedResult) > Abs(divisionResult))
  407. {
  408. return alternativeResult;
  409. }
  410. else
  411. {
  412. return regularMod;
  413. }
  414. }
  415. if (Abs(alternativeResult) < Abs(regularMod))
  416. {
  417. return alternativeResult;
  418. }
  419. else
  420. {
  421. return regularMod;
  422. }
  423. }
  424. public static double Log(double a, double newBase)
  425. {
  426. if (double.IsNaN(a))
  427. {
  428. return a; // IEEE 754-2008: NaN payload must be preserved
  429. }
  430. if (double.IsNaN(newBase))
  431. {
  432. return newBase; // IEEE 754-2008: NaN payload must be preserved
  433. }
  434. if (newBase == 1)
  435. {
  436. return double.NaN;
  437. }
  438. if ((a != 1) && ((newBase == 0) || double.IsPositiveInfinity(newBase)))
  439. {
  440. return double.NaN;
  441. }
  442. return (Log(a) / Log(newBase));
  443. }
  444. [NonVersionable]
  445. public static byte Max(byte val1, byte val2)
  446. {
  447. return (val1 >= val2) ? val1 : val2;
  448. }
  449. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  450. public static decimal Max(decimal val1, decimal val2)
  451. {
  452. return decimal.Max(val1, val2);
  453. }
  454. public static double Max(double val1, double val2)
  455. {
  456. // This matches the IEEE 754:2019 `maximum` function
  457. //
  458. // It propagates NaN inputs back to the caller and
  459. // otherwise returns the larger of the inputs. It
  460. // treats +0 as larger than -0 as per the specification.
  461. if ((val1 > val2) || double.IsNaN(val1))
  462. {
  463. return val1;
  464. }
  465. if (val1 == val2)
  466. {
  467. return double.IsNegative(val1) ? val2 : val1;
  468. }
  469. return val2;
  470. }
  471. [NonVersionable]
  472. public static short Max(short val1, short val2)
  473. {
  474. return (val1 >= val2) ? val1 : val2;
  475. }
  476. [NonVersionable]
  477. public static int Max(int val1, int val2)
  478. {
  479. return (val1 >= val2) ? val1 : val2;
  480. }
  481. [NonVersionable]
  482. public static long Max(long val1, long val2)
  483. {
  484. return (val1 >= val2) ? val1 : val2;
  485. }
  486. [CLSCompliant(false)]
  487. [NonVersionable]
  488. public static sbyte Max(sbyte val1, sbyte val2)
  489. {
  490. return (val1 >= val2) ? val1 : val2;
  491. }
  492. public static float Max(float val1, float val2)
  493. {
  494. // This matches the IEEE 754:2019 `maximum` function
  495. //
  496. // It propagates NaN inputs back to the caller and
  497. // otherwise returns the larger of the inputs. It
  498. // treats +0 as larger than -0 as per the specification.
  499. if ((val1 > val2) || float.IsNaN(val1))
  500. {
  501. return val1;
  502. }
  503. if (val1 == val2)
  504. {
  505. return float.IsNegative(val1) ? val2 : val1;
  506. }
  507. return val2;
  508. }
  509. [CLSCompliant(false)]
  510. [NonVersionable]
  511. public static ushort Max(ushort val1, ushort val2)
  512. {
  513. return (val1 >= val2) ? val1 : val2;
  514. }
  515. [CLSCompliant(false)]
  516. [NonVersionable]
  517. public static uint Max(uint val1, uint val2)
  518. {
  519. return (val1 >= val2) ? val1 : val2;
  520. }
  521. [CLSCompliant(false)]
  522. [NonVersionable]
  523. public static ulong Max(ulong val1, ulong val2)
  524. {
  525. return (val1 >= val2) ? val1 : val2;
  526. }
  527. public static double MaxMagnitude(double x, double y)
  528. {
  529. // This matches the IEEE 754:2019 `maximumMagnitude` function
  530. //
  531. // It propagates NaN inputs back to the caller and
  532. // otherwise returns the input with a larger magnitude.
  533. // It treats +0 as larger than -0 as per the specification.
  534. double ax = Abs(x);
  535. double ay = Abs(y);
  536. if ((ax > ay) || double.IsNaN(ax))
  537. {
  538. return x;
  539. }
  540. if (ax == ay)
  541. {
  542. return double.IsNegative(x) ? y : x;
  543. }
  544. return y;
  545. }
  546. [NonVersionable]
  547. public static byte Min(byte val1, byte val2)
  548. {
  549. return (val1 <= val2) ? val1 : val2;
  550. }
  551. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  552. public static decimal Min(decimal val1, decimal val2)
  553. {
  554. return decimal.Min(val1, val2);
  555. }
  556. public static double Min(double val1, double val2)
  557. {
  558. // This matches the IEEE 754:2019 `minimum` function
  559. //
  560. // It propagates NaN inputs back to the caller and
  561. // otherwise returns the larger of the inputs. It
  562. // treats +0 as larger than -0 as per the specification.
  563. if ((val1 < val2) || double.IsNaN(val1))
  564. {
  565. return val1;
  566. }
  567. if (val1 == val2)
  568. {
  569. return double.IsNegative(val1) ? val1 : val2;
  570. }
  571. return val2;
  572. }
  573. [NonVersionable]
  574. public static short Min(short val1, short val2)
  575. {
  576. return (val1 <= val2) ? val1 : val2;
  577. }
  578. [NonVersionable]
  579. public static int Min(int val1, int val2)
  580. {
  581. return (val1 <= val2) ? val1 : val2;
  582. }
  583. [NonVersionable]
  584. public static long Min(long val1, long val2)
  585. {
  586. return (val1 <= val2) ? val1 : val2;
  587. }
  588. [CLSCompliant(false)]
  589. [NonVersionable]
  590. public static sbyte Min(sbyte val1, sbyte val2)
  591. {
  592. return (val1 <= val2) ? val1 : val2;
  593. }
  594. public static float Min(float val1, float val2)
  595. {
  596. // This matches the IEEE 754:2019 `minimum` function
  597. //
  598. // It propagates NaN inputs back to the caller and
  599. // otherwise returns the larger of the inputs. It
  600. // treats +0 as larger than -0 as per the specification.
  601. if ((val1 < val2) || float.IsNaN(val1))
  602. {
  603. return val1;
  604. }
  605. if (val1 == val2)
  606. {
  607. return float.IsNegative(val1) ? val1 : val2;
  608. }
  609. return val2;
  610. }
  611. [CLSCompliant(false)]
  612. [NonVersionable]
  613. public static ushort Min(ushort val1, ushort val2)
  614. {
  615. return (val1 <= val2) ? val1 : val2;
  616. }
  617. [CLSCompliant(false)]
  618. [NonVersionable]
  619. public static uint Min(uint val1, uint val2)
  620. {
  621. return (val1 <= val2) ? val1 : val2;
  622. }
  623. [CLSCompliant(false)]
  624. [NonVersionable]
  625. public static ulong Min(ulong val1, ulong val2)
  626. {
  627. return (val1 <= val2) ? val1 : val2;
  628. }
  629. public static double MinMagnitude(double x, double y)
  630. {
  631. // This matches the IEEE 754:2019 `minimumMagnitude` function
  632. //
  633. // It propagates NaN inputs back to the caller and
  634. // otherwise returns the input with a larger magnitude.
  635. // It treats +0 as larger than -0 as per the specification.
  636. double ax = Abs(x);
  637. double ay = Abs(y);
  638. if ((ax < ay) || double.IsNaN(ax))
  639. {
  640. return x;
  641. }
  642. if (ax == ay)
  643. {
  644. return double.IsNegative(x) ? x : y;
  645. }
  646. return y;
  647. }
  648. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  649. public static decimal Round(decimal d)
  650. {
  651. return decimal.Round(d, 0);
  652. }
  653. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  654. public static decimal Round(decimal d, int decimals)
  655. {
  656. return decimal.Round(d, decimals);
  657. }
  658. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  659. public static decimal Round(decimal d, MidpointRounding mode)
  660. {
  661. return decimal.Round(d, 0, mode);
  662. }
  663. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  664. public static decimal Round(decimal d, int decimals, MidpointRounding mode)
  665. {
  666. return decimal.Round(d, decimals, mode);
  667. }
  668. [Intrinsic]
  669. public static double Round(double a)
  670. {
  671. // ************************************************************************************
  672. // IMPORTANT: Do not change this implementation without also updating Math.Round(double),
  673. // FloatingPointUtils::round(double), and FloatingPointUtils::round(float)
  674. // ************************************************************************************
  675. // If the number has no fractional part do nothing
  676. // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
  677. if (a == (double)((long)a))
  678. {
  679. return a;
  680. }
  681. // We had a number that was equally close to 2 integers.
  682. // We need to return the even one.
  683. double flrTempVal = Floor(a + 0.5);
  684. if ((a == (Floor(a) + 0.5)) && (FMod(flrTempVal, 2.0) != 0))
  685. {
  686. flrTempVal -= 1.0;
  687. }
  688. return CopySign(flrTempVal, a);
  689. }
  690. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  691. public static double Round(double value, int digits)
  692. {
  693. return Round(value, digits, MidpointRounding.ToEven);
  694. }
  695. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  696. public static double Round(double value, MidpointRounding mode)
  697. {
  698. return Round(value, 0, mode);
  699. }
  700. public static unsafe double Round(double value, int digits, MidpointRounding mode)
  701. {
  702. if ((digits < 0) || (digits > maxRoundingDigits))
  703. {
  704. throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
  705. }
  706. if (mode < MidpointRounding.ToEven || mode > MidpointRounding.ToPositiveInfinity)
  707. {
  708. throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
  709. }
  710. if (Abs(value) < doubleRoundLimit)
  711. {
  712. var power10 = roundPower10Double[digits];
  713. value *= power10;
  714. switch (mode)
  715. {
  716. // Rounds to the nearest value; if the number falls midway,
  717. // it is rounded to the nearest value with an even least significant digit
  718. case MidpointRounding.ToEven:
  719. {
  720. value = Round(value);
  721. break;
  722. }
  723. // Rounds to the nearest value; if the number falls midway,
  724. // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers)
  725. case MidpointRounding.AwayFromZero:
  726. {
  727. double fraction = ModF(value, &value);
  728. if (Abs(fraction) >= 0.5)
  729. {
  730. value += Sign(fraction);
  731. }
  732. break;
  733. }
  734. // Directed rounding: Round to the nearest value, toward to zero
  735. case MidpointRounding.ToZero:
  736. {
  737. value = Truncate(value);
  738. break;
  739. }
  740. // Directed Rounding: Round down to the next value, toward negative infinity
  741. case MidpointRounding.ToNegativeInfinity:
  742. {
  743. value = Floor(value);
  744. break;
  745. }
  746. // Directed rounding: Round up to the next value, toward positive infinity
  747. case MidpointRounding.ToPositiveInfinity:
  748. {
  749. value = Ceiling(value);
  750. break;
  751. }
  752. default:
  753. {
  754. throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
  755. }
  756. }
  757. value /= power10;
  758. }
  759. return value;
  760. }
  761. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  762. public static int Sign(decimal value)
  763. {
  764. return decimal.Sign(value);
  765. }
  766. public static int Sign(double value)
  767. {
  768. if (value < 0)
  769. {
  770. return -1;
  771. }
  772. else if (value > 0)
  773. {
  774. return 1;
  775. }
  776. else if (value == 0)
  777. {
  778. return 0;
  779. }
  780. throw new ArithmeticException(SR.Arithmetic_NaN);
  781. }
  782. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  783. public static int Sign(short value)
  784. {
  785. return Sign((int)value);
  786. }
  787. public static int Sign(int value)
  788. {
  789. return unchecked(value >> 31 | (int)((uint)-value >> 31));
  790. }
  791. public static int Sign(long value)
  792. {
  793. return unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
  794. }
  795. [CLSCompliant(false)]
  796. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  797. public static int Sign(sbyte value)
  798. {
  799. return Sign((int)value);
  800. }
  801. public static int Sign(float value)
  802. {
  803. if (value < 0)
  804. {
  805. return -1;
  806. }
  807. else if (value > 0)
  808. {
  809. return 1;
  810. }
  811. else if (value == 0)
  812. {
  813. return 0;
  814. }
  815. throw new ArithmeticException(SR.Arithmetic_NaN);
  816. }
  817. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  818. public static decimal Truncate(decimal d)
  819. {
  820. return decimal.Truncate(d);
  821. }
  822. public static unsafe double Truncate(double d)
  823. {
  824. ModF(d, &d);
  825. return d;
  826. }
  827. [DoesNotReturn]
  828. private static void ThrowMinMaxException<T>(T min, T max)
  829. {
  830. throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max));
  831. }
  832. }
  833. }