MathgeomGLS

Форк
0
/
Velthuis.BigDecimals.pas 
2521 строка · 96.0 Кб
1
{---------------------------------------------------------------------------}
2
{                                                                           }
3
{ File:       Velthuis.BigDecimals.pas                                      }
4
{ HFunction:  A multiple precision decimal implementation, based on the     }
5
{             BigInteger implementation in Velthuis.BigIntegers.pas.        }
6
{ Language:   Delphi version XE2 or later                                   }
7
{ Author:     Rudy Velthuis                                                 }
8
{ Copyright:  (c) 2016,2017 Rudy Velthuis                                   }
9
{ ------------------------------------------------------------------------- }
10
{                                                                           }
11
{ License:    Redistribution and use in source and binary forms, with or    }
12
{             without modification, are permitted provided that the         }
13
{             following conditions are met:                                 }
14
{                                                                           }
15
{             * Redistributions of source code must retain the above        }
16
{               copyright notice, this list of conditions and the following }
17
{               disclaimer.                                                 }
18
{             * Redistributions in binary form must reproduce the above     }
19
{               copyright notice, this list of conditions and the following }
20
{               disclaimer in the documentation and/or other materials      }
21
{               provided with the distribution.                             }
22
{                                                                           }
23
{ Disclaimer: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS"     }
24
{             AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     }
25
{             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND     }
26
{             FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO        }
27
{             EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE     }
28
{             FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,     }
29
{             OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,      }
30
{             PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     }
31
{             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    }
32
{             AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT   }
33
{             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)        }
34
{             ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   }
35
{             ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                    }
36
{                                                                           }
37
{---------------------------------------------------------------------------}
38

39
{---------------------------------------------------------------------------}
40
{                                                                           }
41
{ Notes:      The interface of BigDecimal is mainly the same as the Java    }
42
{             BigDecimal type. But because Java does not have operator      }
43
{             overloading, it uses methods for all the arithmetic           }
44
{             operations, so it is not a big problem to give these extra    }
45
{             MathContext parameters, e.g for division or conversions.      }
46
{             Division might result in a non-terminating expansion (e.g.    }
47
{             1 / 3 does not terminate, so there must be a given limit on   }
48
{             the number of digits. This generally requires rounding).      }
49
{                                                                           }
50
{             To be able to use overloaded operators, I decided to give     }
51
{             the class DefaultPrecision and DefaultRoundingMode            }
52
{             properties, to be used in any division or conversion that     }
53
{             requires these. Additionally, there are methods that take     }
54
{             Precision or RoundingMode parameters, which do not use the    }
55
{             defaults.                                                     }
56
{                                                                           }
57
{             The names of some of the methods and identifiers were chosen  }
58
{             to be more in line with BigInteger and with other Delphi      }
59
{             functions and constants.                                      }
60
{                                                                           }
61
{             The ToString and ToPlainString methods do follow the Java     }
62
{             interface, i.e. ToString produces scientific notation where   }
63
{             this makes sense while ToPlainString produces plain notation, }
64
{             even if this means that the string can get very long and      }
65
{             contains many zeroes. Both ToString and ToPlainString do not  }
66
{             use local format settings, but use the system invariant       }
67
{             format settings instead. This allows the output of these      }
68
{             methods to be used as valid input for Parse and TryParse (so  }
69
{             called roundtrip conversion).                                 }
70
{             If you want output based on FormatSettings, use my upcoming   }
71
{             NumberFormatter instead.                                      }
72
{                                                                           }
73
{             Based on the Java examples and on my Decimal types, I use a   }
74
{             Scale which is positive for fractions, even if a positive     }
75
{             exponent might make more sense.                               }
76
{                                                                           }
77
{             BigDecimals are immutable. This means that if a method        }
78
{             returns a value that differs from the value of the current    }
79
{             BigDecimal, a new BigDecimal is returned.                     }
80
{                                                                           }
81
{---------------------------------------------------------------------------}
82

83
unit Velthuis.BigDecimals;
84

85
(* TODO: BigDecimals are ssslllooowww. This piece of code, with CIterations = 5*1000*1000,
86

87
    SetLength(arr, CIterations);
88
    pi := '3.14159';
89
    for I := 0 to High(arr) do
90
      arr[I] := BigDecimal(I);
91
    for I := 0 to High(arr) do
92
      arr[I] := arr[I] * pi / (pi * BigDecimal(I) + BigDecimal.One);
93

94
  is 500 times(!) slower than the Double equivalent. That is extremely slow.
95
  Note that simplyfying this to do BigDecimal(I) * pi only once will only take away 1% of that.
96
  It is crucial to find out what makes this code so terribly slow.
97

98
  Note: probably BigInteger.DivMod is the slow part.
99

100
  Note: It might make sense to use a NativeInt to hold the FValue of small BigDecimals, instead
101
  of always BigIntegers.
102
  It might also make sense to make BigInteger.DivMod a lot faster for small values.
103
*)
104

105
interface
106

107
uses
108
  CompilerAndRTLVersions,
109
  System.SysUtils,
110
  System.Math,
111
  Velthuis.BigIntegers;
112

113
{$IF CompilerVersion >= CompilerVersionDelphi2010}   // Delphi 2010
114
  {$DEFINE HasClassConstructors}
115
{$IFEND}
116

117
{$IF CompilerVersion >= CompilerVersionDelphiXE}
118
  {$CODEALIGN 16}
119
  {$ALIGN 16}
120
{$IFEND}
121

122
{$IF CompilerVersion >= CompilerVersionDelphiXE3}
123
  {$LEGACYIFEND ON}
124
{$IFEND}
125

126
{$IF CompilerVersion < CompilerVersionDelphiXE8}
127
  {$IF (DEFINED(WIN32) or DEFINED(CPUX86)) AND NOT DEFINED(CPU32BITS)}
128
    {$DEFINE CPU32BITS}
129
  {$IFEND}
130
  {$IF (DEFINED(WIN64) OR DEFINED(CPUX64)) AND NOT DEFINED(CPU64BITS)}
131
    {$DEFINE CPU64BITS}
132
  {$IFEND}
133
{$IFEND}
134

135
{$IF SizeOf(Extended) > SizeOf(Double)}
136
  {$DEFINE HasExtended}
137
{$IFEND}
138

139
{$DEFINE EXPERIMENTAL}
140

141

142
type
143
  // Note: where possible, existing exception types are used, e.g. EConvertError, EOverflow, EUnderflow,
144
  // EZeroDivide from System.SysUtils, etc.
145

146
  /// <summary>This exception is raised when on rounding, rmUnnecessary is specified, indicating that we
147
  /// "know" that rounding is not necessary, and the code determines that, to get the desired result, rounding is
148
  /// necessary after all.</summary>
149
  ERoundingNecessary = class(Exception);
150
  EIntPowerExponent = class(Exception);
151

152
  PBigDecimal = ^BigDecimal;
153

154
  /// <summary>BigDecimal is a multiple precision floating decimal point binary significand data type. It consists
155
  /// of a BigInteger and a scale, which is the negative decimal exponent.</summary>
156
  /// <remarks><para>BigDecimal "remembers" the precision with which it was initialized. So BigDecimal('1.79') and
157
  /// BigDecimal('1.790000') are distinct values, although they compare as equal.</para>
158
  /// <para>BigDecimals are immutable. This means that any function or operator that returns a different
159
  /// value returns a new BigDecimal.</para></remarks>
160
  BigDecimal = record
161

162
  public
163
    /// <summary>RoundingMode governs which rounding mode is used for certain operations, like division or
164
    /// conversion.</summary>
165
    /// <param name="rmUp">Rounds away from zero</param>
166
    /// <param name="rmDown">Rounds towards zero</param>
167
    /// <param name="rmCeiling">Rounds towards +infinity</param>
168
    /// <param name="rmFloor">Rounds towards -infinity</param>
169
    /// <param name="rmNearestUp">Rounds to nearest higher order digit and, on tie, away from zero</param>
170
    /// <param name="rmNearestDown">Rounds to nearest higher order digit and, on tie, towards zero</param>
171
    /// <param name="rmNearestEven">Rounds to nearest higher order digit and, on tie, to nearest even digit</param>
172
    /// <param name="rmUnnecessary">Assumes an exact result, and raises an exception if rounding is necessary</param>
173
    type
174
      RoundingMode =
175
      (
176
        rmUp,                   // Round away from zero
177
        rmDown,                 // Round towards zero
178
        rmCeiling,              // Round towards +infinity
179
        rmFloor,                // Round towards -infinity
180
        rmNearestUp,            // Round .5 away from 0
181
        rmNearestDown,          // Round .5 towards 0
182
        rmNearestEven,          // Round .5 towards the nearest even value
183
        rmUnnecessary           // Do not round, because operation has exact result
184
      );
185

186
    const
187
      /// <summary>Maximum value a BigDecimal's scale can have</summary>
188
      MaxScale = MaxInt div SizeOf(Velthuis.BigIntegers.TLimb);
189

190
      /// <summary>Minimum value a BigDecimal's scale can have</summary>
191
      MinScale = -MaxScale - 1;
192

193
{$IF defined(CPU32BITS)}
194
      IntPowerExponentThreshold = 128;
195
{$ELSE}
196
      IntPowerExponentThreshold = 256;
197
{$IFEND}
198

199
  private
200
    type
201
      // Error codes to be used when calling the private static BigDecimal.Error method.
202
      TErrorCode = (ecParse, ecDivByZero, ecConversion, ecOverflow, ecUnderflow, ecInvalidArg, ecRounding, ecExponent);
203

204
    var
205
      // The unscaled value of the BigDecimal.
206
      FValue: BigInteger;
207

208
      // The scale which is the power of ten by which the UnscaledValue must be divided to get the BigDecimal value.
209
      // So 1.79 is coded as FValue = 179 and FScale = 2, whereas 1.7900 is coded as FValue = 17900 and FScale = 4.
210
      FScale: Int32;
211

212
      // The precision is the number of digits in FValue. This is originally 0, and calculated when used the first time.
213
      // If this value is not 0, then the precision does not need to be calculated and this value can be used.
214
      FPrecision: Int32;
215

216
    class var
217
      // Default rounding mode. See above.
218
      FDefaultRoundingMode: RoundingMode;
219

220
      // Default precision (number of significant digits) used for e.g. division.
221
      FDefaultPrecision: Integer;
222

223
      // Set this to False if trailing zeroes should not be reduced to the preferred scale after a division.
224
      FReduceTrailingZeros: Boolean;
225

226
      // Default character used to indicate exponent in scientific notation output. Either 'E' or 'e'. Default 'e'.
227
      FExponentDelimiter: Char;
228

229
      // BigDecimal with value -1: unscaled value = -1, scale = 0.
230
      FMinusOne: BigDecimal;
231

232
      // BigDecimal with value 0: unscaled value = 0, scale = 0.
233
      FZero: BigDecimal;
234

235
      // BigDecimal with value 1: unscaled value = 1, scale = 0.
236
      FOne: BigDecimal;
237

238
      // BigDecimal with Value 2: unscaled value = 2, scale = 0.
239
      FTwo: BigDecimal;
240

241
      // BigDecimal with value 10: unscaled value = 10, scale = 0.
242
      FTen: BigDecimal;
243

244
      // BigDecimal with value 0.5: unscaled value = 5, scale = 1.
245
      FHalf: BigDecimal;
246

247
      // BigDecimal with value 0.1: unscaled value = 1, scale = 1.
248
      FOneTenth: BigDecimal;
249

250
{$IFDEF HasClassConstructors}
251
    class constructor InitClass;
252
{$ELSE}
253
    class procedure InitClass; static;
254
{$ENDIF}
255

256
    // Increments Quotient if its current value, the value of the remainder and the given rounding mode and sign require it.
257
    class procedure AdjustForRoundingMode(var Quotient: BigInteger; const Divisor, Remainder: BigInteger; Sign: Integer; Mode: RoundingMode); static;
258

259
    // Divides FValue by a power of ten to remove as many trailing zeros possible without altering its value,
260
    // i.e. it leaves other digits intact, and adjusts the scale accordingly.
261
    // Say we have 1.7932400000000 as value, i.e. [FValue=17932400000000, FScale=13], and the target scale
262
    // is 2, then the result is [179324, 5], which is as close to scale=2 as we can get without altering the value.
263
    class procedure InPlaceRemoveTrailingZeros(var Value: BigDecimal; TargetScale: Integer); static;
264

265
    // Converts the current BigDecimal to sign, significand and exponent for the given significand size in bits.
266
    // Can be used to convert to components for Single, Double and Extended.
267
    class procedure ConvertToFloatComponents(const Value: BigDecimal; SignificandSize: Integer;
268
      var Sign: Integer; var Exponent: Integer; var Significand: UInt64); static;
269

270
    // Converts the current sign, significand and exponent, extracted from a Single, Double or Extended,
271
    // into a BigDecimal.
272
    class procedure ConvertFromFloatComponents(Sign: TValueSign; Exponent: Integer; Significand: UInt64;
273
      var Result: BigDecimal); static;
274

275
    // Raises exceptions where the type depends on the error code and the message on the arguments.
276
    class procedure Error(ErrorCode: TErrorCode; ErrorInfo: array of const); static;
277

278
    // Gets a BigInteger of the given power of five, either from a prefilled array or using BigInteger.Pow.
279
    class function GetPowerOfFive(N: Integer): BigInteger; static;
280

281
    // Gets a BigInteger of the given power of ten, either from a prefilled array or using BigInteger.Pow.
282
    class function GetPowerOfTen(N: Integer): BigInteger; static;
283

284
    // Initialize or reset scale and precision to 0.
285
    procedure Init; inline;
286

287
    // Checks if the NewScale value is a valid scale value. If so, simply returns NewScale. Otherwise, raises
288
    // an appropriate exception.
289
    class function RangeCheckedScale(NewScale: Int32): Integer; static;
290

291
    // Only allows 'e' or 'E' as exponent delimiter for scientific notation output.
292
    class procedure SetExponentDelimiter(const Value: Char); static;
293

294

295
  public
296
    /// <summary>Creates a BigDecimal with given unscaled value and given scale.</summary>
297
    constructor Create(const UnscaledValue: BigInteger; Scale: Integer); overload;
298

299
  {$IFDEF HasExtended}
300
    /// <summary>Creates a BigDecimal with the same value as the given Extended parameter.</summary>
301
    /// <exception cref="EInvalidArgument">EInvalidArgument is raised if the parameter contains a NaN or infinity.</exception>
302
    constructor Create(const E: Extended); overload;
303
  {$ENDIF}
304

305
    /// <summary>Creates a BigDecimal with the same value as the given Double parameter.</summary>
306
    /// <exception cref="EInvalidArgument">EInvalidArgument is raised if the parameter contains a NaN or infinity.</exception>
307
    constructor Create(const D: Double); overload;
308

309
    /// <summary>Creates a BigDecimal with the same value as the given Single parameter.</summary>
310
    /// <exception cref="EInvalidArgument">EInvalidArgument is raised if the parameter contains a NaN or infinity.</exception>
311
    constructor Create(const S: Single); overload;
312

313
    /// <summary>Creates a BigDecimal with the value that results from parsing the given string parameter.</summary>
314
    /// <exception cref="EConvertError">EConvertError is raised if the string cannot be parsed to a valid BigDecimal.</exception>
315
    constructor Create(const S: string); overload;
316

317
    /// <summary>Creates a BigDecimal with the same value as the given BigInteger parameter.</summary>
318
    constructor Create(const UnscaledValue: BigInteger); overload;
319

320
    /// <summary>Creates a BigDecimal with the same value as the given unsigned 64 bit integer parameter.</summary>
321
    constructor Create(const U64: UInt64); overload;
322

323
    /// <summary>Creates a BigDecimal with the same value as the given signed 64 bit integer parameter.</summary>
324
    constructor Create(const I64: Int64); overload;
325

326
    /// <summary>Creates a BigDecimal with the same value as the given unsigned 32 bit integer parameter.</summary>
327
    constructor Create(U32: UInt32); overload;
328

329
    /// <summary>Creates a BigDecimal with the same value as the given signed 32 bit integer parameter.</summary>
330
    constructor Create(I32: Int32); overload;
331

332

333
    // -- Mathematical operators --
334

335
    /// <summary>Adds two BigDecimals. The new scale is Max(Left.Scale, Right.Scale).</summary>
336
    /// <param name="Left">The augend</param>
337
    /// <param name="Right">The addend</param>
338
    /// <returns><code>Result := Left + Right;</code></returns>
339
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
340
    class operator Add(const Left, Right: BigDecimal): BigDecimal;
341

342
    /// <summary>Subtracts two BigDecimals. The new scale is Max(Left.Scale, Right.Scale).</summary>
343
    /// <param name="Left">The minuend</param>
344
    /// <param name="Right">The subtrahend</param>
345
    /// <returns><code>Result := Left - Right;</code></returns>
346
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
347
    class operator Subtract(const Left, Right: BigDecimal): BigDecimal;
348

349
    /// <summary>Multiplies two BigDecimals. The new scale is Left.Scale + Right.Scale.</summary>
350
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
351
    /// <exception cref="EUnderflow">EUnderflow is raised if the result would become too small.</exception>
352
    class operator Multiply(const Left, Right: BigDecimal): BigDecimal;
353

354
    /// <summary><para>Divides two BigDecimals.</para>
355
    /// <para>Uses the default precision and rounding mode to obtain the result.</para>
356
    /// <para>The target scale is <c>Left.Scale - Right.Scale</c>. The result will approach this target scale as
357
    /// much as possible by removing any excessive trailing zeros.</para></summary>
358
    /// <param name="Left">The dividend (enumerator)</param>
359
    /// <param name="Right">The divisor (denominator)</param>
360
    /// <returns><code>Result := Left / Right;</code></returns>
361
    /// <exception cref="EZeroDivide">EZeroDivide is raised if the divisor is zero.</exception>
362
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
363
    /// <exception cref="EUnderflow">EUnderflow is raised if the result would become too small.</exception>
364
    class operator Divide(const Left, Right: BigDecimal): BigDecimal;
365

366
    /// <summary>Divides two BigDecimals to obtain an integral result.</summary>
367
    /// <param name="left">The dividend</param>
368
    /// <param name="Right">The divisor</param>
369
    /// <returns><code>Result := Left div Right;</code></returns>
370
    /// <exception cref="EZeroDivide">EZeroDivide is raised if the divisor is zero.</exception>
371
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
372
    /// <exception cref="EUnderflow">EUnderflow is raised if the result would become too small.</exception>
373
    class operator IntDivide(const Left, Right: BigDecimal): BigDecimal;
374

375
    /// <summary>Returns the remainder after Left is divided by right to an integral value.</summary>
376
    /// <param name="Left">The dividend</param>
377
    /// <param name="Right">The divisor</param>
378
    /// <returns><code>Result := Left - Right * (Left div Right);</code></returns>
379
    /// <exception cref="EZeroDivide">EZeroDivide is raised if the divisor is zero.</exception>
380
    /// <exception cref="EOverflow">EOverflow is raised if the result would become too big.</exception>
381
    /// <exception cref="EUnderflow">EUnderflow is raised if the result would become too small.</exception>
382
    class operator Modulus(const Left, Right: BigDecimal): BigDecimal;
383

384
    /// <summary>Negates the given BigDecimal.</summary>
385
    /// <returns><code>Result := -Value;</code></returns>
386
    class operator Negative(const Value: BigDecimal): BigDecimal;
387

388
    /// <summary>Called when a BigDecimal is preceded by a unary +. Currently a no-op.</summary>
389
    /// <returns><code>Result := +Value;</code></returns>
390
    class operator Positive(const Value: BigDecimal): BigDecimal;
391

392
    /// <summary>Rounds the given BigDecimal to an Int64.</summary>
393
    /// <exception cref="EConvertError">EConvertError is raised if the result is too large to fit in an Int64.</exception>
394
    class operator Round(const Value: BigDecimal): Int64;
395

396
    /// <summary>Truncates (ronds down towards 0) the given BigDecimal to an Int64.</summary>
397
    /// <exception cref="EConvertError">EConvertError is raised if the result is too large to fit in an Int64.</exception>
398
    class operator Trunc(const Value: BigDecimal): Int64;
399

400

401
    // -- Comparison operators --
402

403
    /// <summary>Returns True if Left is mathematically less than or equal to Right.</summary>
404
    /// <param name="Left">The first operand</param>
405
    /// <param name="Right">The second operand</param>
406
    /// <returns><code>Result := Left &lt;= Right;</code></returns>
407
    class operator LessThanOrEqual(const Left, Right: BigDecimal): Boolean;
408

409
    /// <summary>Returns True if Left is mathematically less than Right.</summary>
410
    /// <param name="Left">The first operand</param>
411
    /// <param name="Right">The second operand</param>
412
    /// <returns><code>Result := Left &lt; Right;</code></returns>
413
    class operator LessThan(const left, Right: BigDecimal): Boolean;
414

415
    /// <summary>Returns True if Left is mathematically greater than or equal to Right.</summary>
416
    /// <param name="Left">The first operand</param>
417
    /// <param name="Right">The second operand</param>
418
    /// <returns><code>Result := Left &gt;= Right;</code></returns>
419
    class operator GreaterThanOrEqual(const Left, Right: BigDecimal): Boolean;
420

421
    /// <summary>Returns True if Left is mathematically greater than Right.</summary>
422
    /// <param name="Left">The first operand</param>
423
    /// <param name="Right">The second operand</param>
424
    /// <returns><code>Result := Left &gt; Right;</code></returns>
425
    class operator GreaterThan(const Left, Right: BigDecimal): Boolean;
426

427
    /// <summary>Returns True if Left is mathematically equal to Right.</summary>
428
    /// <param name="Left">The first operand</param>
429
    /// <param name="Right">The second operand</param>
430
    /// <returns><code>Result := Left = Right;</code></returns>
431
    class operator Equal(const left, Right: BigDecimal): Boolean;
432

433
    /// <summary>Returns True if Left is mathematically not equal to Right.</summary>
434
    /// <param name="Left">The first operand</param>
435
    /// <param name="Right">The second operand</param>
436
    /// <returns><code>Result := Left &lt;&gt; Right;</code></returns>
437
    class operator NotEqual(const Left, Right: BigDecimal): Boolean;
438

439

440
    // -- Implicit conversion operators --
441

442
  {$IFDEF HasExtended}
443
    /// <summary>Returns a BigDecimal with the exact value of the given Extended parameter.</summary>
444
    class operator Implicit(const E: Extended): BigDecimal;
445
  {$ENDIF}
446

447
    /// <summary>Returns a BigDecimal with the exact value of the given Double parameter.</summary>
448
    class operator Implicit(const D: Double): BigDecimal;
449

450
    /// <summary>Returns a BigDecimal with the exact value of the given Single parameter.</summary>
451
    class operator Implicit(const S: Single): BigDecimal;
452

453
    /// <summary>Returns a BigDecimal with the value parsed from the given string parameter.</summary>
454
    class operator Implicit(const S: string): BigDecimal;
455

456
    /// <summary>Returns a BigDecimal with the value of the given BigInteger parameter.</summary>
457
    class operator Implicit(const UnscaledValue: BigInteger): BigDecimal;
458

459
    /// <summary>Returns a BigDecimal with the value of the given unsigned 64 bit integer parameter.</summary>
460
    class operator Implicit(const U: UInt64): BigDecimal;
461

462
    /// <summary>Returns a BigDecimal with the value of the given signed 64 bit integer parameter.</summary>
463
    class operator Implicit(const I: Int64): BigDecimal;
464

465
    /// <summary>Returns a BigDecimal with the value of the given unsigned 64 bit integer parameter.</summary>
466
    class operator Implicit(const U: UInt32): BigDecimal;
467

468
    /// <summary>Returns a BigDecimal with the value of the given signed 64 bit integer parameter.</summary>
469
    class operator Implicit(const I: Int32): BigDecimal;
470

471

472
    // -- Explicit conversion operators --
473

474
  {$IFDEF HasExtended}
475
    /// <summary>Returns an Extended with the best approximation of the given BigDecimal value.
476
    /// The conversion uses the default rounding mode.</summary>
477
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
478
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
479
    class operator Explicit(const Value: BigDecimal): Extended;
480
  {$ENDIF}
481

482
    /// <summary>Returns a Double with the best approximation of the given BigDecimal value.
483
    /// The conversion uses the default rounding mode.</summary>
484
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
485
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
486
    class operator Explicit(const Value: BigDecimal): Double;
487

488
    /// <summary>Returns a Single with the best approximation of the given BigDecimal value.
489
    /// The conversion uses the default rounding mode.</summary>
490
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
491
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
492
    class operator Explicit(const Value: BigDecimal): Single;
493

494
    /// <summary>Returns a string representation of the given BigDecimal value.</summary>
495
    class operator Explicit(const Value: BigDecimal): string;
496

497
    /// <summary>Returns a BigInteger with the rounded value of the given BigDecimal value.
498
    /// The conversion uses the rounding mode rmDown, i.e. it truncates.</summary>
499
    class operator Explicit(const Value: BigDecimal): BigInteger;
500

501
    /// <summary>Returns an unsigned 64 bit integer with the rounded value of the given BigDecimal value.
502
    /// The conversion uses the default rounding mode rmDown, i.e. it truncates.</summary>
503
    /// <remarks><para>If the value of the rounded down BigDecimal does not fit in an UInt64, only the low
504
    /// 64 bits of that value are used to form the result.</para>
505
    /// <para>This is analogue to</para>
506
    /// <code>    myByte := Byte(MyUInt64);</code>
507
    /// <para>Only the low 8 bits of myUInt64 are copied to the byte.</para></remarks>
508
    class operator Explicit(const Value: BigDecimal): UInt64;
509

510
    /// <summary>Returns a signed 64 bit integer with the rounded value of the given BigDecimal value.
511
    /// The conversion uses the default rounding mode rmDown, i.e. it truncates.</summary>
512
    /// <remarks><para>If the value of the rounded down BigDecimal does not fit in an Int64, only the low
513
    /// 64 bits of that value are used to form the result.</para>
514
    /// <para>This is analogue to</para>
515
    /// <code>    myByte := Byte(MyUInt64);</code>
516
    /// <para>Only the low 8 bits of myUInt64 are copied to the byte.</para></remarks>
517
    class operator Explicit(const Value: BigDecimal): Int64;
518

519
    /// <summary>Returns an unsigned 32 bit integer with the rounded value of the given BigDecimal value.
520
    /// The conversion uses the default rounding mode rmDown, i.e. it truncates.</summary>
521
    /// <remarks><para>If the value of the rounded down BigDecimal does not fit in an UInt32, only the low
522
    /// 32 bits of that value are used to form the result.</para>
523
    /// <para>This is analogue to</para>
524
    /// <code>    myByte := Byte(MyUInt32);</code>
525
    /// <para>Only the low 8 bits of myUInt32 are copied to the byte.</para></remarks>
526
    class operator Explicit(const Value: BigDecimal): UInt32;
527

528
    /// <summary>Returns a signed 32 bit integer with the rounded value of the given BigDecimal value.
529
    /// The conversion uses the default rounding mode rmDown, i.e. it truncates.</summary>
530
    /// <remarks><para>If the value of the rounded down BigDecimal does not fit in an Int32, only the low
531
    /// 32 bits of that value are used to form the result.</para>
532
    /// <para>This is analogue to</para>
533
    /// <code>    myByte := Byte(MyUInt32);</code>
534
    /// <para>Only the low 8 bits of myUInt32 are copied to the byte.</para></remarks>
535
    class operator Explicit(const Value: BigDecimal): Int32;
536

537

538
    // -- Conversion functions --
539

540
  {$IFDEF HasExtended}
541
    function AsExtended: Extended;
542
  {$ENDIF}
543
    function AsDouble: Double;
544
    function AsSingle: Single;
545
    function AsBigInteger: BigInteger;
546
    function AsUInt64: UInt64;
547
    function AsInt64: Int64;
548
    function AsUInt32: UInt32;
549
    function AsInt32: Int32;
550

551

552
    // -- Mathematical functions --
553

554
    /// <summary>Returns the sum of the given parameters. The new scale is Max(Left.Scale, Right.Scale).</summary>
555
    class function Add(const Left, Right: BigDecimal): BigDecimal; overload; static;
556

557
    /// <summary>Returns the difference of the given parameters. The new scale is Max(Left.Scale, Right.Scale).</summary>
558
    class function Subtract(const Left, Right: BigDecimal): BigDecimal; overload; static;
559

560
    /// <summary>Returns the product ofthe given parameters. The new scale is Left.Scale + Right.Scale.</summary>
561
    class function Multiply(const Left, Right: BigDecimal): BigDecimal; overload; static;
562

563
    /// <summary><para>Returns the quotient of the given parameters. Left is the dividend, Right the divisor.</para>
564
    /// <para>Raises an exception if the value of Right is equal to 0.</para>
565
    /// <para>Uses the default rounding mode and precision.
566
    /// Raises an exception if the rounding mode is rmUnnecessary, but rounding turns out to be necessary.</para>
567
    /// <para>The preferred new scale is Left.Scale - Right.Scale. Removes any trailing zero digits to
568
    /// approach that preferred scale without altering the significant digits.</para></summary>
569
    class function Divide(const Left, Right: BigDecimal): BigDecimal; overload; static;
570

571
    /// <summary><para>Returns the quotient of the given parameters. Left is the dividend, Right the divisor.</para>
572
    /// <para>Raises an exception if the value of Right is equal to 0.</para>
573
    /// <para>Uses the given rounding mode and precision.
574
    /// Raises an exception if the rounding mode is rmUnnecessary, but rounding turns out to be necessary.</para>
575
    /// <para>The preferred new scale is Left.Scale - Right.Scale. Removes any trailing zero digits to
576
    /// approach that preferred scale without altering the significant digits.</para></summary>
577
    class function Divide(const Left, Right: BigDecimal; Precision: Integer; ARoundingMode: RoundingMode): BigDecimal; overload; static;
578

579
    /// <summary><para>Returns the quotient of the given parameters. Left is the dividend, Right the divisor.</para>
580
    /// <para>Raises an exception if the value of Right is equal to 0.</para>
581
    /// <para>Uses the given rounding mode and the default precision.
582
    /// Raises an exception if the rounding mode is rmUnnecessary, but rounding turns out to be necessary.</para>
583
    /// <para>The preferred new scale is Left.Scale - Right.Scale. Removes any trailing zero digits to
584
    /// approach that preferred scale without altering the significant digits.</para></summary>
585
    class function Divide(const Left, Right: BigDecimal; Precision: Integer): BigDecimal; overload; static;
586

587
    /// <summary><para>Returns the quotient of the given parameters. Left is the dividend, Right the divisor.</para>
588
    /// <para>Raises an exception if the value of Right is equal to 0.</para>
589
    /// <para>Uses the default rounding mode and the given precision.
590
    /// Raises an exception if the rounding mode is rmUnnecessary, but rounding turns out to be necessary.</para>
591
    /// <para>The preferred new scale is Left.Scale - Right.Scale. Removes any trailing zero digits to
592
    /// approach that preferred scale without altering the significant digits.</para></summary>
593
    class function Divide(const Left, Right: BigDecimal; ARoundingMode: RoundingMode): BigDecimal; overload; static;
594

595
    /// <summary>Returns the negated value of the given BigDecimal parameter.</summary>
596
    class function Negate(const Value: BigDecimal): BigDecimal; overload; static;
597

598
    /// <summary>Rounds the value of the given BigDecimal parameter to a signed 64 bit integer. Uses the default
599
    /// rounding mode for the conversion.</summary>
600
    class function Round(const Value: BigDecimal): Int64; overload; static;
601

602
    /// <summary>Rounds the value of the given BigDecimal parameter to a signed 64 bit integer. Uses the default
603
    /// rounding mode for the conversion.</summary>
604
    class function Round(const Value: BigDecimal; ARoundingMode: RoundingMode): Int64; overload; static;
605

606
    /// <summary><para>Returns the BigDecimal remainder after the division of the two parameters.</para>
607
    /// <para>Uses the default precision and rounding mode for the division.</para></summary>
608
    /// <returns><para>The result has the value of</para>
609
    /// <code>   Left - (Left / Right).Int * Right</code></returns>
610
    class function Remainder(const Left, Right: BigDecimal): BigDecimal; static;
611

612
    /// <summary>Returns the absolute (non-negative) value of the given BigDecimal.</summary>
613
    class function Abs(const Value: BigDecimal): BigDecimal; overload; static;
614

615
    /// <summary>Returns the square of the given BigDecimal.<summary>
616
    class function Sqr(const Value: BigDecimal): BigDecimal; overload; static;
617

618
    /// <summary>Returns the square root of the given BigDecimal, using the given precision.</summary>
619
    class function Sqrt(const Value: BigDecimal; Precision: Integer): BigDecimal; overload; static;
620

621
    /// <summary>Returns the square root of the given BigDecimal, using the default precision.</summary>
622
    class function Sqrt(const Value: BigDecimal): BigDecimal; overload; static;
623

624
    /// <summary>Returns the integer power of the given BigDecimal, in unlimited precision.</summary>
625
    class function IntPower(const Base: BigDecimal; Exponent: Integer): BigDecimal; overload; static;
626

627
    /// <summary>Returns the integer power of the given BigDecimal, in the given precision.</summary>
628
    class function IntPower(const Base: BigDecimal; Exponent, Precision: Integer): BigDecimal; overload; static;
629

630

631
    // -- Comparison functions --
632

633
    /// <summary>Returns 1 if Left is matehamtically greater than Right, 0 if Left is mathematically equal to Right and
634
    ///  -1 is Left is matheamtically less than Right.</summary>
635
    class function Compare(const Left, Right: BigDecimal): TValueSign; static;
636

637
    /// <summary>Returns the maximum of the two given BigDecimal values.</summary>
638
    class function Max(const Left, Right: BigDecimal): BigDecimal; static;
639

640
    /// <summary>Returns the minimum of the two given BigDecimal values.</summary>
641
    class function Min(const Left, Right: BigDecimal): BigDecimal; static;
642

643

644
    // -- Parsing --
645

646
    /// <summary>Tries to parse the given string as a BigDecimal into Res, using the given format settings.</summary>
647
    /// <returns>Returns only True of the function was successful.</returns>
648
    class function TryParse(const S: string; const Settings: TFormatSettings; out Value: BigDecimal): Boolean;
649
      overload; static;
650

651
    /// <summary>Tries to parse the given string as a BigDecimal into Res, using the system invariant format
652
    /// settings.</summary>
653
    /// <returns>Returns only True of the function was successful.</returns>
654
    class function TryParse(const S: string; out Value: BigDecimal): Boolean;
655
      overload; static;
656

657
    /// <summary>Returns the BigDecimal with a value as parsed from the given string, using the given
658
    /// format settings.</summary>
659
    /// <exception cref="EConvertError">EConvertError is raised if the string cannot be parsed to a valid BigDecimal.</exception>
660
    class function Parse(const S: string; const Settings: TFormatSettings): BigDecimal; overload; static;
661

662
    /// <summary>Returns the BigDecimal with a value as parsed from the given string, using the system
663
    /// invariant format settings.</summary>
664
    /// <exception cref="EConvertError">EConvertError is raised if the string cannot be parsed to a valid BigDecimal.</exception>
665
    class function Parse(const S: string): BigDecimal; overload; static;
666

667

668
    // -- Instance methods --
669

670
    /// <summary>Returns true if the current BigDecimal's value equals zero.</summary>
671
    function IsZero: Boolean;
672

673
    /// <summary>Returns true if the current BigDecimal's value is positive.</summary>
674
    function IsPositive: Boolean;
675

676
    /// <summary>Returns true if the current BigDecimal's value is negative.</summary>
677
    function IsNegative: Boolean;
678

679
    /// <summary>Returns the sign of the current BigDecimal: -1 if negative, 0 if zero, 1 if positive.</summary>
680
    function Sign: TValueSign;
681

682
    /// <summary>Returns the absolute (i.e. non-negative) value of the current BigDecimal.</summary>
683
    function Abs: BigDecimal; overload;
684

685
    /// <summary>Rounds the current BigDecimal to a value with at most Digits digits, using the given rounding
686
    /// mode.</summary>
687
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
688
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
689
    /// <remarks><para>The System.Math.RoundTo function uses the floating point equivalent of rmNearestEven, while
690
    /// System.Math.SimpleRoundTo uses the equivalent of rmNearestUp. This function is more versatile.</para>
691
    /// <para>This is exactly equivalent to</para>
692
    /// <code>    RoundToScale(-Digits, ARoundingMode);</code></remarks>
693
    function RoundTo(Digits: Integer; ARoundingMode: RoundingMode): BigDecimal; overload;
694

695
    /// <summary>Rounds the current BigDecimal to a value with at most Digits digits, using the default rounding
696
    /// mode.</summary>
697
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
698
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
699
    /// <remarks><para>The System.Math.RoundTo function uses the floating point equivalent of rmNearestEven, while
700
    /// System.Math.SimpleRoundTo uses the equivalent of rmNearestUp. This function is more versatile.</para>
701
    /// <para>This is exactly equivalent to</para>
702
    /// <code>    RoundToScale(-Digits, DefaultRoundingMode);</code></remarks>
703
    function RoundTo(Digits: Integer): BigDecimal; overload;
704

705
    /// <summary>Rounds the current BigDecimal to a value with the given scale, using the given rounding
706
    /// mode.</summary>
707
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
708
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
709
    function RoundToScale(NewScale: Integer; ARoundingMode: RoundingMode): BigDecimal;
710

711
    /// <summary>Rounds the current Bigdecimal to a certain precision (number of significant digits).</summary>
712
    /// <exception cref="ERoundingNecessary">ERoundingNecessary is raised if a rounding mode
713
    /// rmUnnecessary was specified but rounding is necessary after all.</exception>
714
    function RoundToPrecision(APrecision: Integer): BigDecimal; overload;
715

716
    /// <summary>Returns a new BigDecimal with the decimal point shifted to the left by the given number of positions</summary>
717
    function MovePointLeft(Digits: Integer): BigDecimal;
718

719
    /// <summary>Returns a new BigDecimal with the decimal point shifted to the right by the given number of positions</summary>
720
    function MovePointRight(Digits: Integer): BigDecimal;
721

722
    /// <summary>Returns a value with any fraction (digits after the decimal point) removed from the current
723
    /// BigDecimal.</summary>
724
    /// <remarks>Example: BigDecimal('1234.5678') results in BigDecimal('1234').</remarks>.
725
    function Int: BigDecimal;
726

727
    /// <summary>Returns a signed 64 bit integer with any fraction (digits after the decimal point) removed
728
    /// from the current BigDecimal.</summary>
729
    /// <exception cref="EConvertError">EConvertError is raised if the result does not fit in an Int64.</exception>
730
    function Trunc: Int64;
731

732
    /// <summary>Returns a BigDecimal containing only the fractional part (digits after the decimal point) of
733
    /// the current BigDecimal.</summary>
734
    /// <remarks>Example: BigDecimal('1234.5678') results in BigDecimal('0.5678').</remarks>
735
    function Frac: BigDecimal;
736

737
    /// <summary>Returns a BigDecimal rounded down, towards negative infinity, to the next integral value.</summary>
738
    /// <remarks>Example: BigDecimal('1234.5678') results in BigDecimal('1234');</remarks>
739
    function Floor: BigDecimal;
740

741
    /// <summary>Returns a BigDecimal rounded up, towards positive infinity, to the next integral value.</summary>
742
    /// <remarks>Example: BigDecimal('1234.5678') results in BigDecimal('1235');</remarks>
743
    function Ceil: BigDecimal;
744

745
    /// <summary>Returns the number of significant digits of the current BigDecimal.</summary>
746
    function Precision: Integer;
747

748
    /// <summary>Returns the reciprocal of the current BigDecimal, using the given precision</summary>
749
    /// <exception cref="EZeroDivide">EZeroDivide is raised if the current BigDecimal is zero.</exception>
750
    function Reciprocal(Precision: Integer): BigDecimal; overload;
751

752
    /// <summary>Returns the reciprocal of the current BigDecimal, using the given precision</summary>
753
    function Reciprocal: BigDecimal; overload;
754

755
    /// <summary>Returns a new BigDecimal with all trailing zeroes (up to the preferred scale) removed from the
756
    /// current BigDecimal. No significant digits will be removed and the numerical value of the result compares
757
    /// as equal to the original value.</summary>
758
    /// <param name="TargetScale">The scale up to which trailing zeroes can be removed. It is possible that
759
    /// fewer zeroes are removed, but never more than necessary to reach the preferred scale.</param>
760
    /// <remarks><para>Note that no rounding is required. Removal stops at the rightmost non-zero digit.</para>
761
    /// <para>Example: BigDecimal('1234.5678900000').RemoveTrailingZeros(3) results in
762
    ///  BigDecimal('1234.56789').</para></remarks>
763
    function RemoveTrailingZeros(TargetScale: Integer): BigDecimal;
764

765
    /// <summary>Returns the square root of the current BigDecimal, with the given precision.</summary>
766
    function Sqrt(Precision: Integer): BigDecimal; overload;
767

768
    /// <summary>Returns the square root of the current BigDecimal, with the default precision.</summary>
769
    function Sqrt: BigDecimal; overload;
770

771
    /// <summary>Returns the integer power of the current BigDecimal, with unlimited precision.</summary>
772
    function IntPower(Exponent: Integer): BigDecimal; overload;
773

774
    /// <summary>Returns the integer power of the current BigDecimal, with the given precision.</summary>
775
    function IntPower(Exponent, Precision: Integer): BigDecimal; overload;
776

777
    /// <summary>Returns the square of the current BigDecimal.</summary>
778
    function Sqr: BigDecimal; overload;
779

780
    /// <summary>Returns the unit of least precision of the current BigDecimal.</summary>
781
    function ULP: BigDecimal;
782

783
    /// <summary>Returns a plain string of the BigDecimal value. This is sometimes called 'decimal notation', and
784
    /// shows the value without the use of exponents.</summary>
785
    function ToPlainString: string; overload;
786

787
    function ToPlainString(const Settings: TFormatSettings): string; overload;
788

789
    /// <summary>Returns a plain string under certain conditions, otherwise returns scientific notation.</summary>
790
    /// <remarks>This does not use FormatSettings. The output is roundtrip, so it is a valid string that can be
791
    /// parsed using Parse() or TryParse().</remarks>
792
    function ToString: string; overload;
793

794
    /// <summary>Returns a plain string under certain conditions, otherwise returns scientific notation.</summary>
795
    /// <remarks>This uses the given FormatSettings for the decimal point Char.</remarks>
796
    function ToString(const Settings: TFormatSettings): string; overload;
797

798

799
    // -- Class properties --
800

801
    /// <summary>The rounding mode to be used if no specific mode is given.</summary>
802
    class property DefaultRoundingMode: RoundingMode read FDefaultRoundingMode write FDefaultRoundingMode;
803

804
    /// <summary>The (maximum) precision to be used for e.g. division if the operation would otherwise result in a
805
    /// non-terminating decimal expansion, i.e. if there is no exact representable decimal result, e.g. when
806
    /// dividing <code>BigDecimal(1) / BigDecimal(3) (= 0.3333333...)</code></summary>
807
    class property DefaultPrecision: Integer read FDefaultPrecision write FDefaultPrecision;
808

809
    /// <summary>If set to False, division will not try to reduce the trailing zeros to match the
810
    /// preferred scale. That is faster, but usually produces bigger decimals</summary>
811
    class property ReduceTrailingZeros: Boolean read FReduceTrailingZeros write FReduceTrailingZeros;
812

813
    /// <summary>The string to be used to delimit the exponent part in scientific notation output.</summary>
814
    /// <remarks>Currently, only 'e' and 'E' are allowed. Setting any other value will be ignored. The default is 'e',
815
    /// because a lower case letter 'e' is usually more easily distinguished between digits '0'..'9'.</remarks>
816
    class property ExponentDelimiter: Char read FExponentDelimiter write SetExponentDelimiter;
817

818
    /// <summary>BigDecimal with value -1: unscaled value = -1, scale = 0.</summary>
819
    class property MinusOne: BigDecimal read FMinusOne;
820

821
    /// <summary>BigDecimal with value 0: unscaled value = 0, scale = 0.</summary>
822
    class property Zero: BigDecimal read FZero;
823

824
    /// <summary>BigDecimal with value 1: unscaled value = 1, scale = 0.</summary>
825
    class property One: BigDecimal read FOne;
826

827
    /// <summary>BigDecimal with value 2: unscaled value = 2, scale = 0.</summary>
828
    class property Two: BigDecimal read FTwo;
829

830
    /// <summary>BigDecimal with value 10: unscaled value = 10, scale = 0.</summary>
831
    class property Ten: BigDecimal read FTen;
832

833
    /// <summary>BigDecimal with value 0.5: unscaled value = 5, scale = 1.</summary>
834
    class property Half: BigDecimal read FHalf;
835

836
    /// <summary>BigDecimal with value 0.1: unscaled value = 1, scale = 1.</summary>
837
    class property OneTenth: BigDecimal read FOneTenth;
838

839

840
    // -- Instance properties --
841

842
    /// <summary>The scale of the current BigDecimal. This is the power of ten by which the UnscaledValue must
843
    /// be divided to get the value of the BigDecimal. Negative scale values denote multiplying by a
844
    /// power of ten.</summary>
845
    /// <remarks>So 1.79e+308 can be stored as UnscaledValue = 179 and Scale = -306, requiring only a small BigInteger
846
    /// with a precision of 3, and not a large one of 308 digits.</remarks>
847
    property Scale: Integer read FScale;
848

849
    /// <summary>The unscaled value of the current BigDecimal. This is the BigInteger than contains the
850
    /// significant digits of the BigDecimal. It is then scaled (in powers of ten) by Scale.</summary>
851
    property UnscaledValue: BigInteger read FValue;
852
  end;
853

854
{$HPPEMIT END '#include "Velthuis.BigDecimals.operators.hpp"'}
855

856
implementation
857

858
{$RANGECHECKS OFF}
859
{$OVERFLOWCHECKS OFF}
860

861
uses
862
  Velthuis.FloatUtils, Velthuis.Numerics, Velthuis.StrConsts;
863

864
var
865
  PowersOfTen: TArray<BigInteger>;
866

867
function InvariantSettings: TFormatSettings;
868
{$IF RTLVersion >= 29.0}
869
begin
870
  // XE8 and higher
871
  Result := TFormatSettings.Invariant;
872
end;
873
{$ELSE}
874
const
875
  Settings: TFormatSettings =
876
  (
877
    CurrencyString: #$00A4;
878
    CurrencyFormat: 0;
879
    CurrencyDecimals: 2;
880
    DateSeparator: '/';
881
    TimeSeparator: ':';
882
    ListSeparator: ',';
883
    ShortDateFormat: 'MM/dd/yyyy';
884
    LongDateFormat: 'dddd, dd MMMMM yyyy HH:mm:ss';
885
    TimeAMString: 'AM';
886
    TimePMString: 'PM';
887
    ShortTimeFormat: 'HH:mm';
888
    LongTimeFormat: 'HH:mm:ss';
889
    ShortMonthNames: ('Jan', 'Feb', 'Mar', 'Apr', 'May,', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
890
    LongMonthNames: ('January', 'February', 'March', 'April', 'May', 'June',
891
                     'July', 'August', 'September', 'October', 'November', 'December');
892
    ShortDayNames: ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
893
    LongDayNames: ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
894
    ThousandSeparator: ',';
895
    DecimalSeparator: '.';
896
    TwoDigitYearCenturyWindow: 50;
897
    NegCurrFormat: 0;
898
  );
899
begin
900
  Result := Settings;
901
end;
902
{$IFEND}
903

904
{ BigDecimal }
905

906
function BigDecimal.Abs: BigDecimal;
907
begin
908
  if Self.FValue.IsNegative then
909
    Result := -Self
910
  else
911
    Result := Self;
912
end;
913

914
class function BigDecimal.Abs(const Value: BigDecimal): BigDecimal;
915
begin
916
  Result := Value.Abs;
917
end;
918

919
//////////////////////////////////////////////////////////////////////////////////////////////////////////
920
//                                                                                                      //
921
//  Adding and subtracting is easy: the operand with the lowest scale is scaled up to the scale of the  //
922
//  other operand. Then the unscaled values (FValue members) can be added or subtracted respectively.   //
923
//                                                                                                      //
924
//////////////////////////////////////////////////////////////////////////////////////////////////////////
925

926
class function BigDecimal.Add(const Left, Right: BigDecimal): BigDecimal;
927
var
928
  L, R: BigInteger;
929
begin
930
  Result.Init;
931
  if Left.IsZero then
932
    if Right.IsZero then
933
      Exit(BigDecimal.Zero)
934
    else
935
      Exit(Right)
936
  else if Right.IsZero then
937
    Exit(Left);
938
  if Left.Scale > Right.Scale then
939
  begin
940
    L := Left.FValue;
941
    R := Right.FValue * GetPowerOfTen(Left.Scale - Right.Scale);
942
    Result.FScale := Left.FScale;
943
  end
944
  else
945
  begin
946
    L := Left.FValue * GetPowerOfTen(Right.Scale - Left.Scale);
947
    R := Right.FValue;
948
    Result.FScale := Right.FScale;
949
  end;
950
  Result.FValue := L + R;
951
end;
952

953
class operator BigDecimal.Add(const Left, Right: BigDecimal): BigDecimal;
954
begin
955
  Result := Add(Left, Right);
956
end;
957

958
////////////////////////////////////////////////////
959
//                                                //
960
//  See comment on rounding near RoundToScale().  //
961
//                                                //
962
////////////////////////////////////////////////////
963

964
class procedure BigDecimal.AdjustForRoundingMode(var Quotient: BigInteger; const Divisor, Remainder: BigInteger; Sign: Integer; Mode: RoundingMode);
965
begin
966
  if not Remainder.IsZero then
967
    case Mode of
968
      rmUp:                                             // 1.7x --> 1.8, -1.7x --> -1.8
969
        Inc(Quotient);
970
      rmDown:                                           // 1.7x --> 1.7, -1.7x --> -1.7
971
        ;                                               // No action required; truncation is default.
972
      rmCeiling:                                        // 1.7x --> 1.8, -1.7x --> -1.7
973
        if Sign >= 0 then
974
          Inc(Quotient);
975
      rmFloor:                                          // 1.7x --> 1.7, -1.7x --> -1.8
976
        if Sign <= 0 then
977
          Inc(Quotient);
978
      rmNearestUp, rmNearestDown, rmNearestEven:
979
        if Remainder + Remainder > Divisor then         // 1.78 --> 1.8, 1.72 --> 1.7, 1.75 --> see next
980
          Inc(Quotient)
981
        else if Remainder + Remainder = Divisor then    // the "Half" condition.
982
          if (Mode = rmNearestUp) or ((Mode = rmNearestEven) and not Quotient.IsEven) then
983
            Inc(Quotient);
984
      rmUnnecessary:                                    // No remainder allowed.
985
        Error(ecRounding, []);
986
    end;
987
end;
988

989
  {$IFDEF HasExtended}
990
    function BigDecimal.AsExtended: Extended;
991
    begin
992
      Result := Extended(Self);
993
      if IsInfinite(Result) then
994
        Error(ecConversion, ['BigDecimal', 'Extended']);
995
    end;
996
  {$ENDIF}
997

998
    function BigDecimal.AsDouble: Double;
999
    begin
1000
      Result := Double(Self);
1001
      if IsInfinite(Result) then
1002
        Error(ecConversion, ['BigDecimal', 'Double']);
1003
    end;
1004

1005
    function BigDecimal.AsSingle: Single;
1006
    begin
1007
      Result := Single(Self);
1008
      if IsInfinite(Result) then
1009
        Error(ecConversion, ['BigDecimal', 'Single']);
1010
    end;
1011

1012
    function BigDecimal.AsBigInteger: BigInteger;
1013
    begin
1014
      Result := BigInteger(Self);
1015
      if Self.Scale > 0 then
1016
        Error(ecRounding, []);
1017
    end;
1018

1019
    function BigDecimal.AsUInt64: UInt64;
1020
    var
1021
      D: BigDecimal;
1022
    begin
1023
      D := Self.RoundToScale(0, rmUnnecessary); // Throws if rounding necessary
1024
      try
1025
        Result := D.UnscaledValue.AsUInt64;     // Throws if too big
1026
      except
1027
        Error(ecConversion, ['BigDecimal', 'UInt64']);
1028
        Result := 0;
1029
      end;
1030
    end;
1031

1032
    function BigDecimal.AsInt64: Int64;
1033
    var
1034
      D: BigDecimal;
1035
    begin
1036
      D := Self.RoundToScale(0, rmUnnecessary);
1037
      try
1038
        Result := D.UnscaledValue.AsInt64;
1039
      except
1040
        Error(ecConversion, ['BigDecimal', 'Int64']);
1041
        Result := 0;
1042
      end;
1043
    end;
1044

1045
    function BigDecimal.AsUInt32: UInt32;
1046
    var
1047
      D: BigDecimal;
1048
    begin
1049
      D := Self.RoundToScale(0, rmUnnecessary);
1050
      try
1051
        Result := D.UnscaledValue.AsCardinal;
1052
      except
1053
        Error(ecConversion, ['BigDecimal', 'UInt32']);
1054
        Result := 0;
1055
      end;
1056
    end;
1057

1058
    function BigDecimal.AsInt32: Int32;
1059
    var
1060
      D: BigDecimal;
1061
    begin
1062
      D := Self.RoundToScale(0, rmUnnecessary);
1063
      try
1064
        Result := D.UnscaledValue.AsInteger;
1065
      except
1066
        Error(ecConversion, ['BigDecimal', 'Int32']);
1067
        Result := 0;
1068
      end;
1069
    end;
1070

1071
// Does a "binary search" to remove trailing zeros. This is much faster (10 times or more) than repeatedly
1072
// dividing by BigInteger.Ten until there is a remainder, even for relatively small numbers of trailing zeros.
1073
// Since this modifies Value, it cannot be made public, but there is a public version of this, called
1074
// RemoveTrailingZeros.
1075
class procedure BigDecimal.InPlaceRemoveTrailingZeros(var Value: BigDecimal; TargetScale: Integer);
1076
var
1077
  L, H, M, LSign: Integer;
1078
  LValue, LDivisor, LQuotient, LRemainder: BigInteger;
1079
  LScale: Integer;
1080
begin
1081
  LSign := Value.FValue.Sign;
1082
  LValue := BigInteger.Abs(Value.FValue);
1083
  LScale := Value.FScale;
1084
  LQuotient := Value.FValue;
1085
  L := TargetScale;
1086
  H := LScale;
1087
  while H > L do
1088
  begin
1089
    // Take the middle value and do a DivMod
1090
    M := (L + H) div 2;
1091
    if M = LScale then
1092
      Break;
1093
    LDivisor := GetPowerOfTen(LScale - M);
1094
    if not LValue.IsEven then
1095
      // Odd numbers can't be divisible by ten, so cut short.
1096
      L := M + 1
1097
    else
1098
    begin
1099
      BigInteger.DivMod(LValue, LDivisor, LQuotient, LRemainder);
1100
      if LRemainder.IsZero then
1101
      begin
1102
        // Remainder was 0, so use the quotient (which has trailing zeroes removed) as new base and try to remove
1103
        // more zeroes on the left.
1104
        H := M;
1105
        LValue := LQuotient;
1106
        // Update the scale accordingly.
1107
        LScale := M;
1108
      end
1109
      else
1110
        // Remainder was not 0, so search further to the right.
1111
        L := M + 1;
1112
    end;
1113
  end;
1114

1115
  // Value and scale may still be off by one.
1116
  if (LScale > TargetScale) and (LValue >= BigInteger.Ten) then
1117
  begin
1118
    BigInteger.DivMod(LValue, BigInteger.Ten, LQuotient, LRemainder);
1119
    if LRemainder.IsZero then
1120
    begin
1121
      LValue := LQuotient;
1122
      Dec(LScale);
1123
    end
1124
  end;
1125

1126
  LValue.Sign := LSign;
1127
  Value.Create(LValue, LScale);
1128
end;
1129

1130
class function BigDecimal.Compare(const Left, Right: BigDecimal): TValueSign;
1131
const
1132
  Values: array[Boolean] of Integer = (-1, 1);
1133
var
1134
  L, R: BigInteger;
1135
begin
1136
  if Left.FValue.IsZero then
1137
    if Right.FValue.IsZero then
1138
      Exit(0)
1139
    else
1140
      Exit(Values[Right.FValue.IsNegative])
1141
  else if Right.FValue.IsZero then
1142
    Exit(Values[Left.FValue.IsPositive]);
1143
  if Left.FScale > Right.FScale then
1144
  begin
1145
    L := Left.FValue;
1146
    R := Right.FValue * GetPowerOfTen(RangeCheckedScale(Left.FScale - Right.FScale));
1147
  end
1148
  else
1149
  begin
1150
    L := Left.FValue * GetPowerOfTen(RangeCheckedScale(Right.FScale - Left.FScale));
1151
    R := Right.FValue;
1152
  end;
1153
  Result := BigInteger.Compare(L, R);
1154
end;
1155

1156
// Converts Value to components for binary FP format, with Significand, binary Exponent and Sign. Significand
1157
// (a.k.a. mantissa) is SignificandSize bits. This can be used for conversion to Extended, Double and Single, and,
1158
// if desired, IEEE 754-2008 binary128 (note: binary32 is equivalent to Single and binary64 to Double).
1159
class procedure BigDecimal.ConvertToFloatComponents(const Value: BigDecimal; SignificandSize: Integer;
1160
  var Sign, Exponent: Integer; var Significand: UInt64);
1161
var
1162
  LDivisor, LQuotient, LRemainder, LLowBit, LSignificand: BigInteger;
1163
  LBitLen, LScale: Integer;
1164
begin
1165
  if Value.FValue.IsNegative then
1166
    Sign := -1
1167
  else
1168
    Sign := 1;
1169

1170
  LScale := Value.Scale;
1171
  Exponent := 0;
1172

1173
  if LScale < 0 then
1174
  begin
1175
    // Get rid of scale while retaining the value:
1176
    // Reduce scale to 0 and at the same time multiply UnscaledValue with 10^-Scale
1177
    // Multiplying by 10^-Scale is equivalent to multiplying with 5^-Scale while decrementing exponent by scale.
1178
    Exponent := -LScale;
1179
    LSignificand := BigInteger.Abs(Value.FValue) * GetPowerOfFive(Exponent);
1180
  end
1181
  else if LScale > 0 then
1182
  begin
1183
    // Get rid of scale, but the other way around: shift left as much as necessary (i.e. multiply by 2^-Scale)
1184
    // and then divide by 5^Scale.
1185
    Exponent := -LScale;
1186
    LDivisor := GetPowerOfFive(LScale);
1187
    LBitLen := LDivisor.BitLength;
1188
    LSignificand := BigInteger.Abs(Value.FValue) shl (LBitLen + SignificandSize - 1);
1189
    Dec(Exponent, LBitLen + SignificandSize - 1);
1190
    BigInteger.DivMod(LSignificand, LDivisor, LQuotient, LRemainder);
1191
    BigDecimal.AdjustForRoundingMode(LQuotient, LDivisor, LRemainder, Sign, rmNearestEven);
1192
    LSignificand := LQuotient;
1193
  end
1194
  else
1195
    LSignificand := BigInteger.Abs(Value.FValue);
1196

1197
  LBitLen := LSignificand.BitLength;
1198
  if LBitLen > SignificandSize then
1199
  begin
1200
    LLowBit := BigInteger.One shl (LBitLen - SignificandSize);
1201
    LRemainder := (LSignificand and (LLowBit - BigInteger.One)) shl 1;
1202
    LSignificand := LSignificand shr (LBitLen - SignificandSize);
1203
    Inc(Exponent, LBitLen - 1);
1204
    if (LRemainder > LLowBit) or ((LRemainder = LLowBit) and not LSignificand.IsEven) then
1205
    begin
1206
      Inc(LSignificand);
1207
      if LSignificand.BitLength > SignificandSize then
1208
      begin
1209
        LSignificand := LSignificand shr 1;
1210
        Inc(Exponent);
1211
      end;
1212
    end
1213
  end
1214
  else
1215
  begin
1216
    LSignificand := LSignificand shl (SignificandSize - LBitLen);
1217
    Inc(Exponent, LBitLen - 1);
1218
  end;
1219

1220
  Significand := LSignificand.AsUInt64;
1221
end;
1222

1223
constructor BigDecimal.Create(const UnscaledValue: BigInteger; Scale: Integer);
1224
begin
1225
  Init;
1226
  FValue := UnscaledValue;
1227
  FScale := Scale;
1228
end;
1229

1230
class procedure BigDecimal.ConvertFromFloatComponents(Sign: TValueSign; Exponent: Integer; Significand: UInt64; var Result: BigDecimal);
1231
type
1232
  TUInt64 = packed record
1233
    Lo, Hi: UInt32;
1234
  end;
1235
var
1236
  NewUnscaledValue: BigInteger;
1237
  NewScale: Integer;
1238
  Shift: Integer;
1239
begin
1240
  Shift := NumberOfTrailingZeros(Significand);
1241

1242
  Significand := Significand shr Shift;
1243
  Inc(Exponent, Shift);
1244

1245
  NewUnscaledValue := Significand;
1246

1247
  NewScale := 0;
1248
  if Exponent < 0 then
1249
  begin
1250
    // To get rid of the binary exponent (make it 0), BigInt must repeatedly be divided by 2.
1251
    // This isn't done directly: on each "iteration", BigInt is multipiled by 5 and then the
1252
    // decimal point is moved by one, which is equivalent with a division by 10.
1253
    // So, effectively, the result is divided by 2.
1254
    // Instead of in a loop, this is done directly using Pow()
1255
    NewUnscaledValue := NewUnscaledValue * BigInteger.Pow(5, -Exponent);
1256
    NewScale := -Exponent;
1257
  end
1258
  else if Exponent > 0 then
1259
    NewUnscaledValue := NewUnscaledValue shl Exponent;
1260

1261
  Result := BigDecimal.Create(NewUnscaledValue, NewScale);
1262
  if Sign < 0 then
1263
    Result := -Result;
1264
end;
1265

1266
constructor BigDecimal.Create(const S: Single);
1267
var
1268
  Significand: UInt64;
1269
  Exponent: Integer;
1270
  Sign: TValueSign;
1271
begin
1272
  if IsInfinite(S) or IsNan(S) then
1273
    Error(ecInvalidArg, ['Single']);
1274

1275
  if S = 0.0 then
1276
  begin
1277
    Self := BigDecimal.Zero;
1278
    Exit;
1279
  end;
1280

1281
  Significand := GetSignificand(S);
1282
  Exponent := GetExponent(S) - 23;
1283
  Sign := System.Math.Sign(S);
1284

1285
  ConvertFromFloatComponents(Sign, Exponent, Significand, Self);
1286
end;
1287

1288
constructor BigDecimal.Create(const D: Double);
1289
var
1290
  Significand: UInt64;
1291
  Exponent: Integer;
1292
  Sign: TValueSign;
1293
begin
1294
  if IsInfinite(D) or IsNan(D) then
1295
    Error(ecInvalidArg, ['Double']);
1296

1297
  if D = 0.0 then
1298
  begin
1299
    Self := BigDecimal.Zero;
1300
    Exit;
1301
  end;
1302

1303
  Significand := GetSignificand(D);
1304
  Exponent := GetExponent(D) - 52;
1305
  Sign := System.Math.Sign(D);
1306

1307
  ConvertFromFloatComponents(Sign, Exponent, Significand, Self);
1308
end;
1309

1310
{$IFDEF HasExtended}
1311
constructor BigDecimal.Create(const E: Extended);
1312
var
1313
  Significand: UInt64;
1314
  Exponent: Integer;
1315
  Sign: TValueSign;
1316
begin
1317
  if IsInfinite(E) or IsNan(E) then
1318
    Error(ecInvalidArg, ['Extended']);
1319

1320
  if E = 0.0 then
1321
  begin
1322
    Self := BigDecimal.Zero;
1323
    Exit;
1324
  end;
1325

1326
  Significand := GetSignificand(E);
1327
  Exponent := GetExponent(E) - 63;
1328
  Sign := System.Math.Sign(E);
1329

1330
  ConvertFromFloatComponents(Sign,Exponent, Significand, Self);
1331
end;
1332
{$ENDIF}
1333

1334
constructor BigDecimal.Create(const S: string);
1335
begin
1336
  Init;
1337
  if not TryParse(S, InvariantSettings, Self) then
1338
    Error(ecParse, [S, 'BigDecimal']);
1339
end;
1340

1341
constructor BigDecimal.Create(const I64: Int64);
1342
begin
1343
  Init;
1344
  FValue := BigInteger.Create(I64);
1345
end;
1346

1347
constructor BigDecimal.Create(const U64: UInt64);
1348
begin
1349
  Init;
1350
  FValue := BigInteger.Create(U64);
1351
end;
1352

1353
constructor BigDecimal.Create(U32: UInt32);
1354
begin
1355
  Init;
1356
  FValue := BigInteger.Create(U32);
1357
end;
1358

1359
constructor BigDecimal.Create(I32: Int32);
1360
begin
1361
  Init;
1362
  FValue := BigInteger.Create(I32);
1363
end;
1364

1365
constructor BigDecimal.Create(const UnscaledValue: BigInteger);
1366
begin
1367
  Init;
1368
  FValue := UnscaledValue;
1369
end;
1370

1371
class function BigDecimal.Divide(const Left, Right: BigDecimal; Precision: Integer;
1372
  ARoundingMode: RoundingMode): BigDecimal;
1373
var
1374
  LQuotient, LRemainder, LDivisor: BigInteger;
1375
  LScale, TargetScale: Integer;
1376
  LSign: Integer;
1377
  LMultiplier: Integer;
1378
begin
1379

1380
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
1381
  // Naively dividing the BigInteger values would result in 0 when e.g. '0.01' and '0.0025' are divided    //
1382
  // (1 div 25 = 0).                                                                                       //
1383
  // So the dividend must be scaled up by at least Precision powers of ten. The end result must be rounded //
1384
  // toward the target scale, which is Left.Scale - Right.Scale.                                           //
1385
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
1386
  // Is there a way to find out beforehand if we need the full precision? Take the above: 0.01/0.0025 = 4. //
1387
  // So we would only need to scale up BigInteger(1) to BigInteger(100) and then divide. Is there a way to //
1388
  // determine this? OTOH, for 0.01/0.003 we need the full precision. Is there a way to determine if a     //
1389
  // division will result in a non-terminating decimal expansion or if it is terminating, where it will    //
1390
  // terminate?                                                                                            //
1391
  // The decimal expansion will be terminating if the divisor can be reduced to 2^n * 5^m, with n,m >= 0,  //
1392
  // in other words, if it can be reduced to only powers of 2 and 5.                                       //
1393
  // Not sure if there is a fast way to determine this. I guess not.                                       //
1394
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
1395

1396
  if Right.FValue.IsZero then
1397
    Error(ecDivByZero, []);
1398
  TargetScale := Left.Scale - Right.Scale;
1399
  if Left.FValue.IsZero then
1400
  begin
1401
    Result.FValue := BigInteger.Zero;
1402
    Result.FScale := TargetScale;
1403
    Exit;
1404
  end;
1405

1406
  // Determine target sign.
1407
  LSign := Left.FValue.Sign xor Right.FValue.Sign;
1408

1409
  // Use positive values (zero was discarded above).
1410
//  LDivisor := BigInteger.Abs(Right.FValue);
1411
  LDivisor := Right.FValue;
1412

1413
  // Determine minimum power of ten with which to multiply the dividend.
1414
  // Previous code used:
1415
  //  LMultiplier := RangeCheckedScale(Precision + Right.Precision - Left.Precision + 3);
1416
  // but the code below is 20% faster - Calculating precision can be slow.
1417
  LMultiplier := RangeCheckedScale(Precision + (Right.FValue.Size - Left.FValue.Size + 1) * 9 + 3);
1418

1419
  // Do the division of the scaled up dividend by the divisor. Quotient and remainder are needed.
1420
  BigInteger.DivMod(Left.FValue * GetPowerOfTen(LMultiplier), LDivisor, LQuotient, LRemainder);
1421

1422
  // Calculate the scale that matches the division.
1423
  LScale := RangeCheckedScale(TargetScale + LMultiplier);
1424

1425
  // Create a preliminary result.
1426
  Result.Create(LQuotient, LScale);
1427

1428
  // Reduce the precision, if necessary.
1429
  // Wow! This is slow. Time reduction of >50% if it could be omitted, e.g. if division were
1430
  // accurate enough already.
1431
  Result := Result.RoundToScale(RangeCheckedScale(LScale + Precision - Result.Precision), ARoundingMode);
1432
  // Can this be combined with InPlaceRemoveTrailingZeros?
1433

1434
  // remove as many trailing zeroes as possible to get as close as possible to the target scale without
1435
  // changing the value.
1436
  // This should be optional, as it is slower.
1437
  if FReduceTrailingZeros then
1438
    InPlaceRemoveTrailingZeros(Result, TargetScale);
1439

1440
  // Finally, set the sign of the result.
1441
  Result.FValue.Sign := LSign;
1442
end;
1443

1444
class function BigDecimal.Divide(const Left, Right: BigDecimal): BigDecimal;
1445
begin
1446
  Result := Divide(Left, Right, DefaultPrecision, DefaultRoundingMode);
1447
end;
1448

1449
class function BigDecimal.Divide(const Left, Right: BigDecimal; Precision: Integer): BigDecimal;
1450
begin
1451
  Result := Divide(Left, Right, Precision, DefaultRoundingMode);
1452
end;
1453

1454
class function BigDecimal.Divide(const Left, Right: BigDecimal; ARoundingMode: RoundingMode): BigDecimal;
1455
begin
1456
  Result := Divide(Left, Right, DefaultPrecision, ARoundingMode);
1457
end;
1458

1459
class operator BigDecimal.Divide(const Left, Right: BigDecimal): BigDecimal;
1460
begin
1461
  Result := Divide(Left, Right, DefaultPrecision, DefaultRoundingMode);
1462
end;
1463

1464
class operator BigDecimal.Equal(const Left, Right: BigDecimal): Boolean;
1465
begin
1466
  Result := Compare(Left, Right) = 0;
1467
end;
1468

1469
class procedure BigDecimal.Error(ErrorCode: TErrorCode; ErrorInfo: array of const);
1470
begin
1471
  // Raise an exception that matches the given error code. The message is determined by the
1472
  // format strings and the Args parameter.
1473
  // Note that, as much as possible, existing exceptions from the Delphi runtime library are used.
1474
  case ErrorCode of
1475
    ecParse:
1476
       // Not a valid BigDecimal string representation.
1477
      raise EConvertError.CreateFmt(SErrorParsingFmt, ErrorInfo);
1478
    ecDivByZero:
1479
      // Division by zero.
1480
      raise EZeroDivide.Create(SDivisionByZero);
1481
    ecConversion:
1482
      // BigDecimal too large for conversion to...
1483
      raise EConvertError.CreateFmt(SConversionFailedFmt, ErrorInfo);
1484
    ecOverflow:
1485
      // Scale would become too low.
1486
      raise EOverflow.Create(SOverflow);
1487
    ecUnderflow:
1488
      // Scale would become too high.
1489
      raise EUnderflow.Create(SUnderflow);
1490
    ecInvalidArg:
1491
      // Parameter is NaN or +/-Infinity.
1492
      raise EInvalidArgument.CreateFmt(SInvalidArgumentFloatFmt, ErrorInfo);
1493
    ecRounding:
1494
      // Rounding was necessary but rmUnnecessary was specified.
1495
      raise ERoundingNecessary.Create(SRounding);
1496
    ecExponent:
1497
      // Exponent outside the allowed range
1498
      raise EIntPowerExponent.Create(SExponent);
1499
    else
1500
      // Invalid operand to operator.
1501
      raise EInvalidOpException.Create(SInvalidOperation);
1502
  end;
1503
end;
1504

1505
class operator BigDecimal.Explicit(const Value: BigDecimal): Single;
1506
var
1507
  LSign, LExponent: Integer;
1508
  LSignificand: UInt64;
1509
  LDiff: Integer;
1510
  LLowBits: UInt32;
1511
  LRem: UInt32;
1512
begin
1513
  if Value.FValue.IsZero then
1514
    Exit(0.0);
1515

1516
  // Convert the given BigDecimal (i.e. UnscaledValue and decimal Scale) to a signficand, sign and binary exponent using
1517
  // the given size of the significand (24 bits for Single).
1518
  ConvertToFloatComponents(Value, 24, LSign, LExponent, LSignificand);
1519

1520
  // Compose calculated sign, significand and exponent into a proper Single.
1521

1522
  // Handle special values:
1523

1524
  // * Values too large (infinities).
1525
  if LExponent > 127 then
1526
    if LSign < 0 then
1527
      Result := NegInfinity
1528
    else
1529
      Result := Infinity
1530
  // * Denormals or below (0).
1531
  else if LExponent < -126 then
1532
  begin
1533
    LDiff := -126 - LExponent;
1534
    if LDiff >= 24 then
1535
      Exit(0.0);
1536
    LLowBits := UInt32(1) shl LDiff;
1537
    LRem := LSignificand and (LLowBits - 1);
1538
    LSignificand := LSignificand shr LDiff;
1539
    if LRem + LRem >= LLowBits then
1540
      Inc(LSignificand);
1541
    if LSign < 0 then
1542
      LSignificand := LSignificand or $80000000;
1543
    Result := PSingle(@LSignificand)^;
1544
  end
1545
  else
1546
    Result := Velthuis.FloatUtils.MakeSingle(LSign, LSignificand, LExponent);
1547
end;
1548

1549
class operator BigDecimal.Explicit(const Value: BigDecimal): Double;
1550
var
1551
  LSign: Integer;
1552
  LExponent: Integer;
1553
  LSignificand: UInt64;
1554
  LDiff: Integer;
1555
  LLowBits: UInt64;
1556
  LRem: UInt64;
1557
begin
1558
  if Value.FValue.IsZero then
1559
    Exit(0.0);
1560

1561
  // Convert the given BigDecimal (i.e. UnscaledValue and decimal Scale) to a significand, sign and binary exponent using
1562
  // the given size of the significand (53 bits for Double).
1563
  ConvertToFloatComponents(Value, 53, LSign, LExponent, LSignificand);
1564

1565
  // Compose calculated sign, significand and exponent into a proper Double.
1566

1567
  // Handle special values:
1568

1569
  // * Values too large (infinities).
1570
  if LExponent > 1023 then
1571
    if LSign < 0 then
1572
      Result := NegInfinity
1573
    else
1574
      Result := Infinity
1575
  // * Denormals or below (0).
1576
  else if LExponent < -1022 then
1577
  begin
1578
    LDiff := -1022 - LExponent;
1579
    if LDiff >= 53 then
1580
      Exit(0.0);
1581

1582
    LLowBits := UInt64(1) shl LDiff;            // mask for the low bits after shift
1583
    LRem := LSignificand and (LLowBits - 1);    // low bits, IOW LSignificand mod 2^LDiff
1584
    LSignificand := LSignificand shr LDiff;     // LSignificand div 2^LDiff
1585
    if (LRem + LRem > LLowBits) or ((LRem + LRem = LLowBits) and (Odd(LSignificand))) then
1586
      Inc(LSignificand);                        // round up
1587
    if LSign < 0 then
1588
      LSignificand := LSignificand or $8000000000000000;
1589
    Result := PDouble(@LSignificand)^;
1590
  end
1591
  else
1592
    Result := Velthuis.FloatUtils.MakeDouble(LSign, LSignificand, LExponent);
1593
end;
1594

1595
{$IFDEF HasExtended}
1596
class operator BigDecimal.Explicit(const Value: BigDecimal): Extended;
1597
var
1598
  LSign, LExponent: Integer;
1599
  LSignificand: UInt64;
1600
  LDiff: Integer;
1601
  LLowBits: UInt64;
1602
  LExtendedRec: packed record
1603
    Man: UInt64;
1604
    Exp: Int16;
1605
  end;
1606
  LRem: UInt64;
1607
begin
1608
  ConvertToFloatComponents(Value, 64, LSign, LExponent, LSignificand);
1609

1610
  // Handle special values
1611
  // * Infinities
1612
  if LExponent > 16383 then
1613
    if LSign < 0 then
1614
      Result := NegInfinity
1615
    else
1616
      Result := Infinity
1617
  else
1618
  // * Denormals
1619
  if LExponent < -16382 then
1620
  begin
1621
    LDiff := -16382 - LExponent;
1622
    if LDiff >= 64 then
1623
      Exit(0.0);
1624
    LLowBits := UInt64(1) shl LDiff;
1625
    LRem := LSignificand and (LLowBits - 1);
1626
    LSignificand := LSignificand shr LDiff;
1627
    if LRem + LRem >= LLowBits then
1628
      Inc(LSignificand);
1629
    LExtendedRec.Man := LSignificand;
1630
    LExtendedRec.Exp := 0;
1631
    if LSign < 0 then
1632
      LExtendedRec.Exp := LExtendedRec.Exp or Int16($8000);
1633
    Result := PExtended(@LExtendedRec)^;
1634
  end
1635
  else
1636
    Result := Velthuis.FloatUtils.MakeExtended(LSign, LSignificand, LExponent);
1637
end;
1638
{$ENDIF}
1639

1640
class operator BigDecimal.Explicit(const Value: BigDecimal): string;
1641
begin
1642
  // General format: uses scientific notation when necessary.
1643
  Result := Value.ToString;
1644
end;
1645

1646
class operator BigDecimal.Explicit(const Value: BigDecimal): UInt64;
1647
var
1648
  Rounded: BigDecimal;
1649
begin
1650
  Rounded := Value.RoundToScale(0, rmDown);
1651
  Result := UInt64(Rounded.FValue and High(UInt64));
1652
end;
1653

1654
class operator BigDecimal.Explicit(const Value: BigDecimal): Int64;
1655
var
1656
  Rounded: BigDecimal;
1657
begin
1658
  Rounded := Value.RoundToScale(0, rmDown);
1659
  Result := Int64(Rounded.FValue);
1660
end;
1661

1662
class operator BigDecimal.Explicit(const Value: BigDecimal): UInt32;
1663
var
1664
  Rounded: BigDecimal;
1665
begin
1666
  Rounded := Value.RoundToScale(0, rmDown);
1667
  Result := UInt32(Rounded.FValue and High(UInt64));
1668
end;
1669

1670
class operator BigDecimal.Explicit(const Value: BigDecimal): Int32;
1671
var
1672
  Rounded: BigDecimal;
1673
begin
1674
  Rounded := Value.RoundToScale(0, rmDown);
1675
  Result := Int32(Rounded.FValue);
1676
end;
1677

1678
function BigDecimal.Frac: BigDecimal;
1679
begin
1680
  Result := BigDecimal.Abs(Self - Self.Int());
1681
end;
1682

1683
function BigDecimal.Floor: BigDecimal;
1684
begin
1685
  if Scale > 0 then
1686
    Result := Self.RoundToScale(0, rmFloor)
1687
  else
1688
    Result := Self;
1689
end;
1690

1691
function BigDecimal.Ceil: BigDecimal;
1692
begin
1693
  if Scale > 0 then
1694
    Result := Self.RoundToScale(0, rmCeiling)
1695
  else
1696
    Result := Self;
1697
end;
1698

1699
class operator BigDecimal.Explicit(const Value: BigDecimal): BigInteger;
1700
var
1701
  Rounded: BigDecimal;
1702
begin
1703
  Rounded := Value.RoundToScale(0, rmDown);
1704
  Result := Rounded.FValue;
1705
end;
1706

1707
// Note: 5^N = 10^N div 2^N = 10^N shr N;
1708
// Powers of five are required when converting a decimal scale/unscaled value combination to a binary
1709
// exponent/significand combination with the same value.
1710
class function BigDecimal.GetPowerOfFive(N: Integer): BigInteger;
1711
begin
1712
  Result := GetPowerOfTen(N) shr N;
1713
end;
1714

1715
// Since a scale denotes powers of ten, powers of ten are required as either multiplicator or divisor.
1716
class function BigDecimal.GetPowerOfTen(N: Integer): BigInteger;
1717
begin
1718
  if N >= 0 then
1719
  begin
1720
    // If index outside array, enlarge the array.
1721
    if N > High(PowersOfTen) then
1722
      SetLength(PowersOfTen, N + 1);
1723
    Result := PowersOfTen[N];
1724

1725
    // If the value read is 0, it is obviously invalid, so calculate power and store it at this index.
1726
    if Result.IsZero then
1727
    begin
1728
      Result := BigInteger.Pow(BigInteger.Ten, N);
1729
      PowersOfTen[N] := Result;
1730
    end;
1731
  end;
1732
end;
1733

1734
class operator BigDecimal.GreaterThan(const Left, Right: BigDecimal): Boolean;
1735
begin
1736
  Result := Compare(Left, Right) > 0;
1737
end;
1738

1739
class operator BigDecimal.GreaterThanOrEqual(const Left, Right: BigDecimal): Boolean;
1740
begin
1741
  Result := Compare(Left, Right) >= 0;
1742
end;
1743

1744
class operator BigDecimal.Implicit(const S: Single): BigDecimal;
1745
begin
1746
  Result.Create(S);
1747
end;
1748

1749
class operator BigDecimal.Implicit(const D: Double): BigDecimal;
1750
begin
1751
  Result.Create(D);
1752
end;
1753

1754
{$IFDEF HasExtended}
1755
class operator BigDecimal.Implicit(const E: Extended): BigDecimal;
1756
begin
1757
  Result.Create(E);
1758
end;
1759
{$ENDIF}
1760

1761
class operator BigDecimal.Implicit(const S: string): BigDecimal;
1762
begin
1763
  Result.Create(S);
1764
end;
1765

1766
class operator BigDecimal.Implicit(const U: UInt64): BigDecimal;
1767
begin
1768
  Result.Create(U);
1769
end;
1770

1771
class operator BigDecimal.Implicit(const I: Int64): BigDecimal;
1772
begin
1773
  Result.Create(I);
1774
end;
1775

1776
class operator BigDecimal.Implicit(const U: UInt32): BigDecimal;
1777
begin
1778
  Result.Create(U);
1779
end;
1780

1781
class operator BigDecimal.Implicit(const I: Int32): BigDecimal;
1782
begin
1783
  Result.Create(I);
1784
end;
1785

1786
class operator BigDecimal.Implicit(const UnscaledValue: BigInteger): BigDecimal;
1787
begin
1788
  Result.Create(UnscaledValue);
1789
end;
1790

1791
procedure BigDecimal.Init;
1792
begin
1793
  FScale := 0;
1794
  FPrecision := 0;
1795
end;
1796

1797
{$IFDEF HasClassConstructors}
1798
class constructor BigDecimal.InitClass;
1799
{$ELSE}
1800
class procedure BigDecimal.InitClass;
1801
{$ENDIF}
1802
var
1803
  I: Integer;
1804
  B: BigInteger;
1805
begin
1806
  SetLength(PowersOfTen, 64);
1807
  B := BigInteger.One;
1808
  for I := Low(PowersOfTen) to High(PowersOfTen) do
1809
  begin
1810
    PowersOfTen[I] := B;
1811
    B := B * BigInteger.Ten;
1812
  end;
1813

1814
  // My default. More or less arbitrary.
1815
  BigDecimal.FDefaultPrecision := 64;
1816

1817
  // The most used rounding mode in Delphi, AFAIK.
1818
  BigDecimal.FDefaultRoundingMode := rmNearestEven;
1819

1820
  // Reduce trialing zeros to target scale after division by default.
1821
  BigDecimal.FReduceTrailingZeros := True;
1822

1823
  // I prefer the lower case 'e', because it is more visible between a number of decimal digits.
1824
  // IOW, the 'e' in 1.23456789e+345 has, IMO, a little higher visibility than in the 'E' in 1.23456789E+345
1825
  BigDecimal.FExponentDelimiter := 'e';
1826

1827
  // The usual constants.
1828
  BigDecimal.FMinusOne := BigDecimal.Create(BigInteger.MinusOne, 0);
1829
  BigDecimal.FZero := BigDecimal.Create(BigInteger.Zero, 0);
1830
  BigDecimal.FOne := BigDecimal.Create(BigInteger.One, 0);
1831
  BigDecimal.FTwo := BigDecimal.Create(BigInteger(2), 0);
1832
  BigDecimal.FTen := BigDecimal.Create(BigInteger.Ten, 0);
1833
  BigDecimal.FHalf := BigDecimal.Create(BigInteger(5), 1);
1834
  BigDecimal.FOneTenth := BigDecimal.Create(BigInteger(1), 1);
1835

1836
  ///////////////////////////////////////////////////////////////////////////////////////////////
1837
  // Note: one might expect constants like pi or e, but since BigDecimal relies on a certain   //
1838
  // precision, there can be no constants for such values. The coming BigDecimalMath unit will //
1839
  // however contain functions to determine them to a given precision.                         //
1840
  ///////////////////////////////////////////////////////////////////////////////////////////////
1841

1842
end;
1843

1844
function BigDecimal.Int: BigDecimal;
1845
begin
1846
  Result := RoundToScale(0, rmDown);
1847
end;
1848

1849
class operator BigDecimal.IntDivide(const Left, Right: BigDecimal): BigDecimal;
1850
var
1851
  LTargetScale: Integer;
1852
  LRequiredPrecision: Integer;
1853
begin
1854
  LTargetScale := Left.FScale - Right.FScale;
1855
  if Left.Abs < Right.Abs then
1856
  begin
1857
    Result.FValue := BigInteger.Zero;
1858
    Result.FScale := LTargetScale;
1859
    Exit;
1860
  end;
1861

1862
  if Left.FValue.IsZero and not Right.FValue.IsZero then
1863
    Exit(Left.RoundToScale(LTargetScale, rmUnnecessary));
1864

1865
  LRequiredPrecision := RangeCheckedScale(Left.Precision + 3 * Right.Precision + System.Abs(LTargetScale) + 3);
1866
  Result := Divide(Left, Right, LRequiredPrecision, rmDown);
1867

1868
  if Result.FScale > 0 then
1869
  begin
1870
    Result := Result.RoundToScale(0, rmDown);
1871
    InPlaceRemoveTrailingZeros(Result, LTargetScale);
1872
  end;
1873

1874
  if Result.Scale < LTargetScale then
1875
    Result := Result.RoundToScale(LTargetScale, rmUnnecessary);
1876
end;
1877

1878
class function BigDecimal.IntPower(const Base: BigDecimal; Exponent, Precision: Integer): BigDecimal;
1879
var
1880
  LBase: BigDecimal;
1881
  LNegativeExp: Boolean;
1882
begin
1883
  if Exponent = 0 then
1884
    Exit(BigDecimal.One);
1885

1886
  LNegativeExp := Exponent < 0;
1887
  if LNegativeExp then
1888
    Exponent := -Exponent;
1889

1890
  if Exponent > 9999999 then
1891
    Error(ecExponent, []);
1892

1893
  if (Base.Precision > 8) and (Exponent >= IntPowerExponentThreshold) then
1894
  begin
1895
    Result := One;
1896
    LBase := Base;
1897
    while Exponent <> 0 do
1898
    begin
1899
      if Odd(Exponent) then
1900
        Result := (Result * LBase).RoundToPrecision(Precision + 3);
1901
      LBase := (LBase * LBase).RoundToPrecision(Precision + 3);
1902
      Exponent := Exponent shr 1;
1903
    end;
1904
  end
1905
  else
1906
    Result := IntPower(Base, Exponent);
1907

1908
  if LNegativeExp then
1909
    Result := Result.Reciprocal(Precision)
1910
  else
1911
    Result := Result.RoundToPrecision(Precision);
1912

1913
  if Result.Scale < Precision then
1914
    Result := Result.RemoveTrailingZeros(0);
1915
end;
1916

1917
class function BigDecimal.IntPower(const Base: BigDecimal; Exponent: Integer): BigDecimal;
1918
var
1919
  LBase: BigDecimal;
1920
  LNegativeExp: Boolean;
1921
begin
1922

1923
  if Exponent = 0 then
1924
    Exit(BigDecimal.One);
1925

1926
  LNegativeExp := Exponent < 0;
1927
  if LNegativeExp then
1928
    Exponent := -Exponent;
1929

1930
  if Exponent > 9999999 then
1931
    Error(ecExponent, []);
1932

1933
  Result := One;
1934
  LBase := Base;
1935
  while Exponent <> 0 do
1936
  begin
1937
    if Odd(Exponent) then
1938
      Result := Result * LBase;
1939
    LBase := LBase * LBase;
1940
    Exponent := Exponent shr 1;
1941
  end;
1942

1943
  if LNegativeExp then
1944
    Result := BigDecimal.Divide(BigDecimal.One, Result, DefaultPrecision);
1945
end;
1946

1947
function BigDecimal.IntPower(Exponent, Precision: Integer): BigDecimal;
1948
begin
1949
  Result := IntPower(Self, Exponent, Precision);
1950
end;
1951

1952
function BigDecimal.IntPower(Exponent: Integer): BigDecimal;
1953
begin
1954
  Result := IntPower(Self, Exponent);
1955
end;
1956

1957
function BigDecimal.IsZero: Boolean;
1958
begin
1959
  Result := FValue.IsZero;
1960
end;
1961

1962
function BigDecimal.IsPositive: Boolean;
1963
begin
1964
  Result := FValue.IsPositive;
1965
end;
1966

1967
function BigDecimal.IsNegative: Boolean;
1968
begin
1969
  Result := FValue.IsNegative;
1970
end;
1971

1972
class operator BigDecimal.LessThan(const left, Right: BigDecimal): Boolean;
1973
begin
1974
  Result := Compare(Left, Right) < 0;
1975
end;
1976

1977
class operator BigDecimal.LessThanOrEqual(const Left, Right: BigDecimal): Boolean;
1978
begin
1979
  Result := Compare(Left, Right) <= 0;
1980
end;
1981

1982
class function BigDecimal.Max(const Left, Right: BigDecimal): BigDecimal;
1983
begin
1984
  if Compare(Left, Right) > 0 then
1985
    Result := Left
1986
  else
1987
    Result := Right;
1988
end;
1989

1990
class function BigDecimal.Min(const Left, Right: BigDecimal): BigDecimal;
1991
begin
1992
  if Compare(Left, Right) < 0 then
1993
    Result := Left
1994
  else
1995
    Result := Right;
1996
end;
1997

1998
class operator BigDecimal.Modulus(const Left, Right: BigDecimal): BigDecimal;
1999
begin
2000
  Result := Remainder(Left, Right);
2001
end;
2002

2003
function BigDecimal.MovePointLeft(Digits: Integer): BigDecimal;
2004
var
2005
  NewScale: Integer;
2006
begin
2007
  NewScale := RangeCheckedscale(Scale + Digits);
2008
  Result := BigDecimal.Create(FValue, NewScale);
2009
  if Result.FScale < 0 then
2010
    Result.FScale := 0;
2011
end;
2012

2013
function BigDecimal.MovePointRight(Digits: Integer): BigDecimal;
2014
var
2015
  NewScale: Integer;
2016
begin
2017
  NewScale := RangeCheckedScale(Scale - Digits);
2018
  Result := BigDecimal.Create(FValue, NewScale);
2019
  if Result.FScale < 0 then
2020
    Result.FScale := 0;
2021
end;
2022

2023
class operator BigDecimal.Multiply(const Left, Right: BigDecimal): BigDecimal;
2024
begin
2025
  Result := Multiply(Left, Right);
2026
end;
2027

2028
///////////////////////////////////////////////////////////////////////////////////////
2029
//                                                                                   //
2030
//  Multiplication is the easiest: multiply the unscaled values and add the scales.  //
2031
//                                                                                   //
2032
///////////////////////////////////////////////////////////////////////////////////////
2033

2034
class function BigDecimal.Multiply(const Left, Right: BigDecimal): BigDecimal;
2035
begin
2036
  Result.Init;
2037
  Result.FScale := RangeCheckedScale(Left.FScale + Right.FScale);
2038
  Result.FValue := Left.FValue * Right.FValue;
2039
end;
2040

2041
class function BigDecimal.Negate(const Value: BigDecimal): BigDecimal;
2042
begin
2043
  Result.Init;
2044
  Result.FValue := -Value.FValue;
2045
  Result.FScale := Value.FScale;
2046
end;
2047

2048
class operator BigDecimal.Negative(const Value: BigDecimal): BigDecimal;
2049
begin
2050
  Result := Negate(Value);
2051
end;
2052

2053
class operator BigDecimal.NotEqual(const Left, Right: BigDecimal): Boolean;
2054
begin
2055
  Result := Compare(left, Right) <> 0;
2056
end;
2057

2058
class function BigDecimal.Parse(const S: string; const Settings: TFormatSettings): BigDecimal;
2059
begin
2060
  Result.Init;
2061
  if not TryParse(S, Settings, Result) then
2062
    Error(ecParse, [S, 'BigDecimal']);
2063
end;
2064

2065
class function BigDecimal.Parse(const S: string): BigDecimal;
2066
begin
2067
  Result.Init;
2068
  if not TryParse(S, Result) then
2069
    Error(ecParse, [S, 'BigDecimal']);
2070
end;
2071

2072
class operator BigDecimal.Positive(const Value: BigDecimal): BigDecimal;
2073
begin
2074
  Result.Init;
2075
  Result := Value;
2076
end;
2077

2078
function BigDecimal.Precision: Integer;
2079
type
2080
  CardRec = packed record
2081
    Lo: Cardinal;
2082
    Hi: Integer;
2083
  end;
2084
const
2085
  // 1292913986 is Log10(2) * 1^32.
2086
  CMultiplier = Int64(1292913986);
2087
var
2088
  Full: Int64;
2089
begin
2090
  Result := FPrecision;
2091
  if Result = 0 then
2092
  begin
2093
    //Note: Both 9999 ($270F) and 10000 ($2710) have a bitlength of 14, but 9999 has a precision of 4, while 10000 has a precision of 5.
2094
    //      In other words: BitLength is not a good enough measure for precision. The test with the power of ten is necessary.
2095
    Full := Int64(FValue.BitLength + 1) * CMultiplier;
2096
    Result := CardRec(Full).Hi;
2097
    if (GetPowerOfTen(Result) <= Abs(FValue)) or (Result = 0) then
2098
      Inc(Result);
2099
    FPrecision := Result;
2100
  end;
2101
end;
2102

2103
// Checks new scale for over- or underflow. Returns new scale.
2104
class function BigDecimal.RangeCheckedScale(NewScale: Int32): Integer;
2105
begin
2106
  if NewScale > MaxScale then
2107
    Error(ecUnderflow, [])
2108
  else if NewScale < MinScale then
2109
    Error(ecOverflow, []);
2110
  Result := NewScale;
2111
end;
2112

2113
function BigDecimal.Reciprocal(Precision: Integer): BigDecimal;
2114
begin
2115
  Result := Divide(BigDecimal.One, Self, Precision, DefaultRoundingMode);
2116
end;
2117

2118
function BigDecimal.Reciprocal: BigDecimal;
2119
begin
2120
  Result := Divide(BigDecimal.One, Self, DefaultPrecision, DefaultRoundingMode);
2121
end;
2122

2123
class function BigDecimal.Remainder(const Left, Right: BigDecimal): BigDecimal;
2124
var
2125
  LQuotient: BigDecimal;
2126
begin
2127
  Result.Init;
2128
  LQuotient := Left div Right;
2129
  Result := Left - LQuotient * Right;
2130
end;
2131

2132
function BigDecimal.RemoveTrailingZeros(TargetScale: Integer): BigDecimal;
2133
begin
2134
  Result := Self;
2135
  if (TargetScale >= FScale) or (Precision = 1) then
2136
    Exit;
2137
  FPrecision := 0;
2138
  InPlaceRemoveTrailingZeros(Result, TargetScale);
2139
end;
2140

2141
class function BigDecimal.Round(const Value: BigDecimal): Int64;
2142
begin
2143
  Result := Round(Value, DefaultRoundingMode);
2144
end;
2145

2146
class function BigDecimal.Round(const Value: BigDecimal; ARoundingMode: RoundingMode): Int64;
2147
var
2148
  Rounded: BigDecimal;
2149
begin
2150
  Result := 0;
2151
  Rounded := Value.RoundTo(0, ARoundingMode);
2152
  try
2153
    Result := Rounded.FValue.AsInt64;
2154
  except
2155
    Error(ecConversion, ['BigDecimal', 'Int64']);
2156
  end;
2157
end;
2158

2159
class operator BigDecimal.Round(const Value: BigDecimal): Int64;
2160
begin
2161
  Result := BigDecimal.Round(Value);
2162
end;
2163

2164
function BigDecimal.RoundTo(Digits: Integer): BigDecimal;
2165
begin
2166
  Result := RoundToScale(-Digits, DefaultRoundingMode);
2167
end;
2168

2169
function BigDecimal.RoundTo(Digits: Integer; ARoundingMode: RoundingMode): BigDecimal;
2170
begin
2171
  Result := RoundToScale(-Digits, ARoundingMode);
2172
end;
2173

2174
function BigDecimal.RoundToPrecision(APrecision: Integer): BigDecimal;
2175
var
2176
  PrecisionDifference: Integer;
2177
begin
2178
  PrecisionDifference := APrecision - Self.Precision;
2179
  Result := RoundTo(-(Scale + PrecisionDifference));
2180
end;
2181

2182
///////////////////////////////////////////////////////////////////////////////////////////////////////
2183
//                                                                                                   //
2184
//  Note:                                                                                            //
2185
//      Rounding is done in several parts of this unit. Instead of using the classic bitwise         //
2186
//      methodology (guard, round and sticky bits), I like to use the remainder after a              //
2187
//      division by a power of ten.                                                                  //
2188
//                                                                                                   //
2189
//      Division truncates, so the first four rounding modes, rmDown, rmUp, rmCeiling and            //
2190
//      rmFloor are easy: truncate and then look if you must add one to the quotient, depending      //
2191
//      on these rounding modes only (and on the sign).                                              //
2192
//                                                                                                   //
2193
//      But the next three, rmNearestUp, rmNearestDown and rmNearestEven, depend on whether the      //
2194
//      remainder is "half" of the low bit. That is how the remainder is used: if                    //
2195
//      remainder + remainder > divisor, we must round up, if it is < divisor we must round down,    //
2196
//      and if = divisor, the rounding mode determines if the quotient must be incremented or not.   //
2197
//                                                                                                   //
2198
//      This principle is used throughout this unit.                                                 //
2199
//                                                                                                   //
2200
///////////////////////////////////////////////////////////////////////////////////////////////////////
2201

2202
function BigDecimal.RoundToScale(NewScale: Integer; ARoundingMode: RoundingMode): BigDecimal;
2203
var
2204
  LScaleDifference: Integer;
2205
  LValue, LDivisor: BigInteger;
2206
  LRemainder, LQuotient: BigInteger;
2207
  LSign: Integer;
2208
begin
2209
  Result.Init;
2210
  LScaleDifference := RangeCheckedScale(Self.Scale - NewScale);
2211
  if LScaleDifference > 0 then
2212
  begin
2213
    LDivisor := GetPowerOfTen(LScaleDifference);
2214
    LSign := FValue.Sign;
2215
    LValue := BigInteger.Abs(FValue);
2216
    BigInteger.DivMod(LValue, LDivisor, LQuotient, LRemainder);
2217
    AdjustForRoundingMode(LQuotient, LDivisor, LRemainder, LSign, ARoundingMode);
2218
    Result.FValue := LSign * LQuotient;
2219
  end
2220
  else if LScaleDifference < 0 then
2221
    Result.FValue := Self.FValue * GetPowerOfTen(-LScaleDifference)
2222
  else
2223
    Result.FValue := Self.FValue;
2224
  Result.FScale := NewScale;
2225
end;
2226

2227
class procedure BigDecimal.SetExponentDelimiter(const Value: Char);
2228
begin
2229
  if (Value = 'e') or (Value = 'E') then
2230
    FExponentDelimiter := Value;
2231
end;
2232

2233
function BigDecimal.Sign: TValueSign;
2234
begin
2235
  Result := FValue.Sign;
2236
end;
2237

2238
class function BigDecimal.Sqr(const Value: BigDecimal): BigDecimal;
2239
begin
2240
  Result.Init;
2241
  Result.FValue := BigInteger.Sqr(Value.FValue);
2242
  Result.FScale := RangeCheckedScale(Value.FScale + Value.FScale);
2243
end;
2244

2245
function BigDecimal.Sqr: BigDecimal;
2246
begin
2247
  Result := BigDecimal.Sqr(Self);
2248
end;
2249

2250
class function BigDecimal.Sqrt(const Value: BigDecimal; Precision: Integer): BigDecimal;
2251
begin
2252
  Result := Value.Sqrt(System.Math.Max(Precision, DefaultPrecision));
2253
end;
2254

2255
class function BigDecimal.Sqrt(const Value: BigDecimal): BigDecimal;
2256
begin
2257
  Result := Value.Sqrt(System.Math.Max(DefaultPrecision, Value.Precision));
2258
end;
2259

2260
function BigDecimal.Sqrt(Precision: Integer): BigDecimal;
2261
var
2262
  LMultiplier: Integer;
2263
  LValue: BigInteger;
2264
begin
2265
  // Note: the following self-devised algorithm works. I don't yet know if it can be optimized.
2266
  // With "works", I mean that if A := B.Sqrt, then (A*A).RoundToScale(B.Scale) = B.
2267
  Result.Init;
2268
  Precision := System.Math.Max(Precision, 2 * Self.Precision);
2269

2270
  // Determine a suitable factor to multiply FValue by to get a useful precision
2271
  LMultiplier := RangeCheckedScale(Precision - Self.Precision + 1);
2272
  if Odd(LMultiplier + Self.Scale) then
2273
    Inc(LMultiplier);
2274

2275
  // If the multiplier > 0, then multiply BigInteger by 10^LMultiplier
2276
  if LMultiplier > 0 then
2277
    LValue := Self.FValue * GetPowerOfTen(LMultiplier)
2278
  else
2279
    LValue := Self.FValue;
2280

2281
  // Using BigInteger.Sqrt should already be pretty close to the desired result.
2282
  Result.FValue := BigInteger.Sqrt(LValue);
2283
  Result.FScale := RangeCheckedScale(Self.Scale + LMultiplier) div 2;
2284

2285
  // Round the result and remove any unnecessary trailing zeroes.
2286
  Result := Result.RoundToScale(RangeCheckedScale(Result.FScale + Precision div 2 - Result.Precision + 1), DefaultRoundingMode);
2287
  InPlaceRemoveTrailingZeros(Result, System.Math.Min(Self.Scale, Self.Scale div 2));
2288
end;
2289

2290
function BigDecimal.Sqrt: BigDecimal;
2291
begin
2292
  Result := Self.Sqrt(DefaultPrecision);
2293
end;
2294

2295
class function BigDecimal.Subtract(const Left, Right: BigDecimal): BigDecimal;
2296
var
2297
  A, B: BigInteger;
2298
begin
2299
  Result.Init;
2300
  if Left.Scale > Right.Scale then
2301
  begin
2302
    A := Left.FValue;
2303

2304
    // There is no need to use RangeCheckedScale, because one scale is simply changed to the other, and both
2305
    // were already in range.
2306
    B := Right.FValue * GetPowerOfTen(Left.Scale - Right.Scale);
2307
    Result.FScale := Left.Scale;
2308
  end
2309
  else
2310
  begin
2311
    A := Left.FValue * GetPowerOfTen(Right.Scale - Left.Scale);
2312
    B := Right.FValue;
2313
    Result.FScale := Right.Scale;
2314
  end;
2315
  Result.FValue := A - B;
2316
end;
2317

2318
class operator BigDecimal.Subtract(const Left, Right: BigDecimal): BigDecimal;
2319
begin
2320
  Result := Subtract(Left, Right);
2321
end;
2322

2323
// Returns decimal notation (i.e. without using exponents).
2324
function BigDecimal.ToPlainString(const Settings: TFormatSettings): string;
2325
var
2326
  S: string;
2327
  LNegative: Boolean;
2328
  LScale, LLength: Integer;
2329
begin
2330
  LNegative := FValue.IsNegative;
2331
  S := BigInteger.Abs(FValue).ToString(10);
2332
  LScale := Self.Scale;
2333
  LLength := Length(S);
2334
  if LScale < 0 then
2335
    Result := S + StringOfChar('0', -LScale)
2336
  else if LScale = 0 then
2337
    Result := S
2338
  else if LScale >= LLength then
2339
    Result := '0' + Settings.DecimalSeparator + StringOfChar('0', LScale - LLength) + S
2340
  else
2341
    Result := Copy(S, 1, LLength - LScale) + Settings.DecimalSeparator + Copy(S, LLength - LScale + 1, MaxInt);
2342
  if LNegative then
2343
    Result := '-' + Result;
2344
end;
2345

2346
function BigDecimal.ToPlainString: string;
2347
begin
2348
  Result := ToPlainString(InvariantSettings);
2349
end;
2350

2351
function BigDecimal.ToString: string;
2352
begin
2353
  Result := ToString(InvariantSettings);
2354
end;
2355

2356
function BigDecimal.ToString(const Settings: TFormatSettings): string;
2357
var
2358
  AdjustedExponent: Integer;
2359
  PlainText: string;
2360
  Negative: Boolean;
2361
begin
2362
  Negative := FValue.IsNegative;
2363
  PlainText := BigInteger.Abs(FValue).ToString(10);
2364
  AdjustedExponent := Length(PlainText) - 1 - Self.Scale;
2365
  if (Self.Scale >= 0) and (AdjustedExponent >= -6) then
2366
    Result := ToPlainString(Settings)
2367
  else
2368
  begin
2369
    // Exponential notation
2370
    if Length(PlainText) > 1 then
2371
      PlainText := PlainText[1] + Settings.DecimalSeparator + Copy(PlainText, 2, MaxInt);
2372
    PlainText := PlainText + FExponentDelimiter;
2373
    if AdjustedExponent >= 0 then
2374
      PlainText := PlainText + '+';
2375
    PlainText := PlainText + IntToStr(AdjustedExponent);
2376
    if Negative then
2377
      PlainText := '-' + PlainText;
2378
    Result := PlainText;
2379
  end;
2380
end;
2381

2382
function BigDecimal.Trunc: Int64;
2383
var
2384
  Rounded: BigDecimal;
2385
begin
2386
  Result := 0; // Avoid warning.
2387
  Rounded := Self.RoundTo(0, rmDown);
2388
  try
2389
    Result := Rounded.FValue.AsInt64;
2390
  except
2391
    Error(ecConversion, ['BigDecimal', 'Int64']);
2392
  end;
2393
end;
2394

2395
class operator BigDecimal.Trunc(const Value: BigDecimal): Int64;
2396
begin
2397
  Result := Value.Trunc;
2398
end;
2399

2400
// Converts string with national settings to invariant string and then calls TryParse(string, BigDecimal).
2401
class function BigDecimal.TryParse(const S: string; const Settings: TFormatSettings; out Value: BigDecimal): Boolean;
2402
var
2403
  InvariantString: string;
2404
  I: Integer;
2405
begin
2406
  SetLength(InvariantString, Length(S));
2407
  for I := 1 to Length(S) do
2408
  begin
2409
    if S[I] = Settings.DecimalSeparator then
2410
      InvariantString[I] := '.'
2411
    else if S[I] = Settings.ThousandSeparator then
2412
      InvariantString[I] := ','
2413
    else
2414
      InvariantString[I] := S[I];
2415
  end;
2416
  Result := TryParse(InvariantString, Value);
2417
end;
2418

2419
class function BigDecimal.TryParse(const S: string; out Value: BigDecimal): Boolean;
2420
var
2421
  LIsNegative: Boolean;
2422
  LIsNegativeExponent: Boolean;
2423
  LExponent: Integer;
2424
  LNumDecimals: Integer;
2425
  LDecimalPointPos: PChar;
2426
  LTrimmedS: string;
2427
  LPtr: PChar;
2428
  LChr: Char;
2429
  LIntValue: string;
2430
begin
2431
  Value.Init;
2432
  Result := False;
2433
  LIntValue := '';
2434
  LTrimmedS := Trim(S);
2435
  LPtr := PChar(LTrimmedS);
2436
  if LPtr^ = #0 then
2437
    Exit;
2438
  LIsNegative := False;
2439
  LIsNegativeExponent := False;
2440
  LDecimalPointPos := nil;
2441
  if (LPtr^ = '+') or (LPtr^ = '-') then
2442
  begin
2443
    LIsNegative := (LPtr^ = '-');
2444
    Inc(LPtr);
2445
  end;
2446
  if LPtr^ = #0 then
2447
    Exit;
2448
  Value.FValue := BigInteger.Zero;
2449
  LNumDecimals := 0;
2450

2451
  // Parse text up to any exponent.
2452
  LChr := LPtr^;
2453
  while (LChr <> #0) and (LChr <> 'e') and (LChr <> 'E') do  // DO NOT TRANSLATE!
2454
  begin
2455
    case LChr of
2456
      '0'..'9':
2457
        LIntValue := LIntvalue + LChr;
2458
      ',':
2459
        ; // Ignore thousand-separators.
2460
      '.':
2461
        if Assigned(LDecimalPointPos) then
2462
          // Decimal point was parsed already, so exit indicating invalid result.
2463
          Exit
2464
        else
2465
          LDecimalPointPos := LPtr;
2466
      else
2467
        Exit;
2468
    end;
2469
    Inc(LPtr);
2470
    LChr := LPtr^;
2471
  end;
2472

2473
  // Parsed significand to end or up to first 'e' or 'E'.
2474
  if Assigned(LDecimalPointPos) then
2475
    LNumDecimals := LPtr - LDecimalPointPos - 1;
2476

2477
  LExponent := 0;
2478
  if (LChr = 'e') or (LChr = 'E') then  // DO NOT TRANSLATE!
2479
  begin
2480
    // Parse exponent
2481
    Inc(LPtr);
2482
    if (LPtr^ = '+') or (LPtr^ = '-') then
2483
    begin
2484
      LIsNegativeExponent := (LPtr^ = '-');
2485
      Inc(LPtr);
2486
    end;
2487
    while LPtr^ <> #0 do
2488
    begin
2489
      case LPtr^ of
2490
        '0'..'9':
2491
          LExponent := LExponent * 10 + Ord(LPtr^) - Ord('0');
2492
        else
2493
          Exit;
2494
      end;
2495
      Inc(LPtr);
2496
    end;
2497
  end;
2498
  if LIsNegativeExponent then
2499
    LExponent := -LExponent;
2500
  LNumDecimals := LNumDecimals - LExponent;
2501

2502
  Value.FScale := LNumDecimals;
2503
  Value.FValue := BigInteger(LIntValue);
2504
  if not Value.FValue.IsZero and LIsNegative then
2505
    Value.FValue.SetSign(-1);
2506
  Result := True;
2507
end;
2508

2509
function BigDecimal.ULP: BigDecimal;
2510
begin
2511
  Result.FPrecision := 1;
2512
  Result.FValue := BigInteger.One;
2513
  Result.FScale := Self.Scale;
2514
end;
2515

2516
{$IFNDEF HasClassConstructors}
2517
initialization
2518
  BigDecimal.InitClass;
2519
{$ENDIF}
2520

2521
end.
2522

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.