{$local nested-comments}{ gmpop.inc -- GMP (GNU multiple precision) functions as operators Copyright 1998-2005 by Frank Heckenbach This include file is an attempt to make it easier to use the multiple precision routines of the GMP library as operators, like operations on ordinary numbers, in Pascal programs compiled with the GNU Pascal compiler. However, with the current state of the compiler, this is not possible in a completely seamless way. Currently, this file is only for real numbers, but it should be possible to do it quite similarly for integers. The routines in this file might, of course, contain some bugs. If you find a problem, please report it to me at the mail address above. But before you try to use this file, please read the following notes. You will hardly be able to use it correctly without reading them, because there is a number of things to pay attention to. To use this file, you need the GNU Pascal (see below for the version required) and the GMP library, version 2.0.2 or newer. This file gmpop.inc is an include file, not a unit, because most routines here are very short and declared inline for reasons of efficiency, and inline routines can't be defined in a unit yet. Besides, this file contains some preprocessor macros for convenience, which also do not work across units. With some features that might get implemented in future versions of the compiler, it might be possible to turn it into a unit. All of the routines here come in two versions: one for ordinary real numbers of type Real, and one for the GMP type mpf_t. The versions are distinguished by the conditional define USE_GMP. So it is possible to easily compile two versions of a program, one using Real which gives limited precision but more speed, and one with GMP, yielding unlimited precision (as far as memory suffices), but slower. Usage: ====== To use this file, just include it into a program: {$i gmpop.inc} This file uses the GMP unit for the GMP version, so you do not have to put a `uses GMP' statementin your program. Variables: ========== Variables and parameters can be declared (in both the Real and the GMP version) of type TRealPar. However, the big drawback currently is that each variable has to be initialized with InitReal before usage, and cleared up with DoneReal afterwards. Failing to use InitReal will often result in segfaults. Failing to use DoneReal will not result in bugs, but in memory leaks. To simplify usage, there is the type TRealVar (actually it's a macro, because types with initializers don't work yet; but it can be thought of as being a type). Variables of this type are initialized automatically upon declaration. This saves the InitReal call. As the next step, the DoneReal call at the end of a variable's life time can be saved by never letting its life time end, i.e. by making it static. (Making local variables static is not a generally recommended practice, but here, it can also be a bit more efficient, since it saves some memory allocations and deallocations.) For convenience, the type (actually again a macro) TReal already contains the `static' declaration (only for GMP, not for Real; so if for some reason you want a static variable in both versions, declare it as `static TReal'). However, this mechanism does not always work. In particular, local variables of recursive routines must generally not be static. Components within structures (records or arrays) can't be declared static, and their initializers syntactically don't look the way TRealVar uses them. And finally, of course, dynamic variables can't be static. In all of these cases, you have to declare them as TRealPar, and do the InitReal/DoneReal yourself. Pointers to TReal variables can be declared of type PReal. Taking the address of TReal variables, and dereferencing PReal pointers is straightforward, and for allocating/deallocating them with New/Dispose, see the previous paragraph. Computed values: ================ Computed values, i.e. values resulting from the use of operators or functions from this file, are automatically initialized and cleaned up. This is achieved by giving them a different type (TRealValue -- but this type should never have to be used outside of this file), and providing each routine in two versions, one taking variables (TRealPar) as arguments, and one taking values (TRealValue). This is mostly transparent to use, except that the two versions of functions have different names: the one that takes values has a `Val' appended to its name. For operators, it is transparent, thanks to operator overloading. In the Real version, TRealValue is the same as TReal and both versions of a function/operator are equivalent. Assignments: ============ Variables of type TRealPar (or TRealVar or TReal) can't be assigned to each other with a simple `:=' because their old value has to be cleaned up, and the new value has to be copied if it comes from another variable. To assign the values of other variables or computed values to them, you have to use AssignReal or AssignRealVal, respectively. Besides, there are functions AssignRealPlainReal and AssignRealInteger, to directly assign Real and Integer values to them. CAVEAT: Assignments between TReal variables with `:=' can't be caught by the compiler since the variables are of the same type and therefore seem to be correct to the compiler. However, they lead to severe problems, and probably hard to find bugs. So check all the `:='s in your program carefully. Parameters: =========== Reference (`var') parameters are straightforward. They can be declared as `var Foo: TRealPar' and be used in the normal way. Const parameters can be declared as `const Foo: TRealPar', but only variables can be used as actual parameters. If you need to pass computed values, you have to use value parameters instead. Value parameters can be declared as `Foo: TRealPar'. However, since they are new variables, they have to be cleaned up with DoneReal at the end of the routine (and before each `Exit' or `Return'). To pass actual parameters to them, you have to use PassReal or PassRealVal, respectively. These routines initialize the parameters, so you must not call InitReal for them within the routine (doing so would destroy the values that were passed). CAVEAT: Passing TReal variables without using PassReal leads to the same problems as assignments between TReal variables. Operators: ========== The following operators are supported: +, -, *, /, =, <>, >, <, >=, <=. They are overloaded for the case that one operands is TReal and the other one is TReal, LongestReal, Real, LongestInt or Integer. Computed values are allowed wherever a TReal is accepted. Due to the very strict type checking with overlaoded operators, the compiler might not always recognize the operators. This can be solved by using temporary variables of the wanted type. If you get error messages about pointer arithmetics, this might be an indication of such a problem. Routines: ========= The following functions and procedures are supported. Each one also exists in a version for computed values with a `Val' appended to its name: Real2PlainReal, RoundReal, AbsReal, SqrReal, SqrtReal, ExpReal, LnReal, WriteReal, WriteStrReal. Additionally, there are two input routines, ReadReal and ReadStrReal which, of course, do not have a `Val' version. There is no synopsis of all the functions here, please refer to their declarations. Precision: ========== If you haven't done so yet, please read the GMP documentation. Among other things, you will learn that GMP reals do not use infinite precision (because that would take an infinite amount of CPU time and memory ;-), but only a precision explicitly requested. Using this file does not change this fact. If you don't do anything about it, it will use GMP's default precision which is usually about the same as that of ordinary Doubles. You can increase (and later decrease again, if needed) the precision used by calling the SetPrecisionReal routine. It can be called at any time in a program. After changing the precision, new variables will be created with that precision, and previously created variables will be changed to the new precision as soon as they're assigned to. Since the necessary precision of input numbers is usually not known, the ReadReal and ReadStrReal routines have a SetPrecision parameter which, if set, causes the (global) precision to be increased at least as much as necessary to represent the input number (but never decreased). In the Real version, the SetPrecisionReal routine and the SetPrecision parameters are, of course, only dummies without any effect. Efficiency: =========== Since all of the routines in the version for Doubles are inlined, the efficiency of that version of a program should not suffer if compiled with optimization. The efficiency of the GMP version, however, is not optimal, because values have to be created and destroyed more often than usually necessary. Therefore, it might be worth rewriting tight inner loops in separate versions with direct GMP calls. You can use `{$ifdef USE_GMP}' to separate them from the normal versions and make use of the fact that TRealPar is actually mpf_t, in order to use your variables with the GMP routines. They will have been initialized to GMP if they have been assigned to, but only calling InitReal or declaring variables of type TRealVar or TReal will *not* initialize them to GMP. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. }{$endlocal} {$gnu-pascal} {$if __GPC_RELEASE__ < 20041017} {$error This include file requires GPC release 20041017 or newer.} {$endif} {$ifdef USE_GMP} uses GMP; type PReal = ^TRealPar; TRealPar = mpf_t; {$define TRealVar TRealPar Value (-1, -1, 0, nil)} { @@ does (did?) not work as a type declaration } {$define TReal TRealVar; attribute (static)} { @@ make this possible as a type declaration? } TRealValue = ^TRealPar; { @@ record r: TRealPar end; ? } var RealPrecision: MedCard = 0; procedure SetPrecisionReal (NewPrecision: MedCard); attribute (unused); var Temp: mpf_t; begin mpf_set_default_prec (NewPrecision); mpf_init (Temp); RealPrecision := mpf_get_prec (Temp); { Get the actual precision used } mpf_clear (Temp) end; function Real_Inited (const a: TRealPar): Boolean; attribute (inline, unused); begin Real_Inited := a.mp_prec <> -1 end; procedure InitReal (var a: TRealPar); attribute (inline, unused); begin a.mp_prec := -1 end; procedure DoneReal (var a: TRealPar); attribute (inline, unused); begin if Real_Inited (a) then mpf_clear (a) end; procedure RInit (var a: TRealPar); attribute (inline, unused); begin if not Real_Inited (a) then mpf_init (a); if mpf_get_prec (a) < RealPrecision then mpf_set_prec (a, RealPrecision) end; procedure RealValueDone (a: TRealValue); attribute (inline, unused); begin mpf_clear (a^); Dispose (a) end; procedure AssignReal (var a: TRealPar; const b: TRealPar); attribute (inline, unused); begin RInit (a); mpf_set (a, b) end; procedure AssignRealVal (var a: TRealPar; b: TRealValue); attribute (inline, unused); begin DoneReal (a); a := b^; Dispose (b) end; procedure AssignRealPlainReal (var a: TRealPar; b: Real); attribute (inline, unused); begin RInit (a); mpf_set_d (a, b) end; procedure AssignRealInteger (var a: TRealPar; b: Integer); attribute (inline, unused); begin RInit (a); mpf_set_si (a, b) end; function PassReal (const a: TRealPar) = b: TRealPar; attribute (inline, unused); begin mpf_init_set (b, a) end; function PassRealVal (a: TRealValue) = b: TRealPar; attribute (inline, unused); begin b := a^; Dispose (a) end; function Real2PlainReal (const a: TRealPar): Real; attribute (inline, unused); begin Real2PlainReal := mpf_get_d (a) end; function Real2PlainRealVal (a: TRealValue): Real; attribute (inline, unused); begin Real2PlainRealVal := Real2PlainReal (a^); RealValueDone (a) end; function RoundReal (const a: TRealPar): LongInt; attribute (inline, unused); begin RoundReal := Round (Real2PlainReal (a)) end; function RoundRealVal (a: TRealValue): LongInt; attribute (inline, unused); begin RoundRealVal := Round (Real2PlainRealVal (a)) end; {$define DECLARE_LONGESTINT(SYMBOL, PAR, RESULTTYPE) operator SYMBOL (PAR; b: LongestInt) = c: RESULTTYPE; attribute (inline, unused); begin if (b >= Low (Integer)) and (b <= High (Integer)) then c := a SYMBOL Integer (b) else c := a SYMBOL Real (b) end; operator SYMBOL (b: LongestInt; PAR) = c: RESULTTYPE; attribute (inline, unused); begin if (b >= Low (Integer)) and (b <= High (Integer)) then c := Integer (b) SYMBOL a else c := Real (b) SYMBOL a end; } {$define DECLARE_ARITHMETIC_OPERATORS_PLAIN(MPF_NAME, SYMBOL, PLAINTYPE) operator SYMBOL (const a: TRealPar; b: PLAINTYPE) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_d (c^, b); MPF_NAME (c^, a, c^) end; operator SYMBOL (a: TRealValue; b: PLAINTYPE) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_d (c^, b); MPF_NAME (c^, a^, c^); RealValueDone (a) end; operator SYMBOL (a: PLAINTYPE; const b: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_d (c^, a); MPF_NAME (c^, c^, b) end; operator SYMBOL (a: PLAINTYPE; b: TRealValue) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_d (c^, a); MPF_NAME (c^, c^, b^); RealValueDone (b) end; } {$define DECLARE_ARITHMETIC_OPERATORS(MPF_NAME, SYMBOL) DECLARE_ARITHMETIC_OPERATORS_PLAIN(MPF_NAME, SYMBOL, Real) DECLARE_ARITHMETIC_OPERATORS_PLAIN(MPF_NAME, SYMBOL, LongestReal) operator SYMBOL (const a, b: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init (c^); MPF_NAME (c^, a, b) end; operator SYMBOL (const a: TRealPar; b: TRealValue) = c: TRealValue; attribute (inline, unused); begin MPF_NAME (b^, a, b^); c := b end; operator SYMBOL (a: TRealValue; const b: TRealPar) = c: TRealValue; attribute (inline, unused); begin MPF_NAME (a^, a^, b); c := a end; operator SYMBOL (a, b: TRealValue) = c: TRealValue; attribute (inline, unused); begin MPF_NAME (a^, a^, b^); c := a; RealValueDone (b) end; operator SYMBOL (const a: TRealPar; b: Integer) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_si (c^, b); MPF_NAME (c^, a, c^) end; operator SYMBOL (a: TRealValue; b: Integer) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_si (c^, b); MPF_NAME (c^, a^, c^); RealValueDone (a) end; operator SYMBOL (a: Integer; const b: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_si (c^, a); MPF_NAME (c^, c^, b) end; operator SYMBOL (a: Integer; b: TRealValue) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init_set_si (c^, a); MPF_NAME (c^, c^, b^); RealValueDone (b) end; DECLARE_LONGESTINT (SYMBOL, const a: TRealPar, TRealValue) DECLARE_LONGESTINT (SYMBOL, a: TRealValue, TRealValue) } DECLARE_ARITHMETIC_OPERATORS (mpf_add, +) DECLARE_ARITHMETIC_OPERATORS (mpf_sub, -) DECLARE_ARITHMETIC_OPERATORS (mpf_mul, *) DECLARE_ARITHMETIC_OPERATORS (mpf_div, /) {$define DECLARE_COMPARISON_OPERATORS_PLAIN(SYMBOL, PLAINTYPE) operator SYMBOL (const a: TRealPar; b: PLAINTYPE) = c: Boolean; attribute (inline, unused); var t: mpf_t; begin mpf_init_set_d (t, b); c := mpf_cmp (a, t) SYMBOL 0; mpf_clear (t) end; operator SYMBOL (a: TRealValue; b: PLAINTYPE) = c: Boolean; attribute (inline, unused); var t: mpf_t; begin mpf_init_set_d (t, b); c := mpf_cmp (a^, t) SYMBOL 0; mpf_clear (t); RealValueDone (a) end; operator SYMBOL (a: PLAINTYPE; const b: TRealPar) = c: Boolean; attribute (inline, unused); var t: mpf_t; begin mpf_init_set_d (t, a); c := mpf_cmp (t, b) SYMBOL 0; mpf_clear (t) end; operator SYMBOL (a: PLAINTYPE; b: TRealValue) = c: Boolean; attribute (inline, unused); var t: mpf_t; begin mpf_init_set_d (t, a); c := mpf_cmp (t, b^) SYMBOL 0; mpf_clear (t); RealValueDone (b) end; } {$define DECLARE_COMPARISON_OPERATORS(SYMBOL, INVSYMBOL) DECLARE_COMPARISON_OPERATORS_PLAIN(SYMBOL, Real) DECLARE_COMPARISON_OPERATORS_PLAIN(SYMBOL, LongestReal) operator SYMBOL (const a, b: TRealPar) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp (a, b) SYMBOL 0 end; operator SYMBOL (const a: TRealPar; b: TRealValue) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp (a, b^) SYMBOL 0; RealValueDone (b) end; operator SYMBOL (a: TRealValue; const b: TRealPar) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp (a^, b) SYMBOL 0; RealValueDone (a) end; operator SYMBOL (a, b: TRealValue) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp (a^, b^) SYMBOL 0; RealValueDone (a); RealValueDone (b) end; operator SYMBOL (const a: TRealPar; b: Integer) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp_si (a, b) SYMBOL 0 end; operator SYMBOL (a: TRealValue; b: Integer) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp_si (a^, b) SYMBOL 0; RealValueDone (a) end; operator SYMBOL (a: Integer; const b: TRealPar) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp_si (b, a) INVSYMBOL 0 end; operator SYMBOL (a: Integer; b: TRealValue) = c: Boolean; attribute (inline, unused); begin c := mpf_cmp_si (b^, a) INVSYMBOL 0; RealValueDone (b) end; DECLARE_LONGESTINT (SYMBOL, const a: TRealPar, Boolean) DECLARE_LONGESTINT (SYMBOL, a: TRealValue, Boolean) } DECLARE_COMPARISON_OPERATORS ( =, =) DECLARE_COMPARISON_OPERATORS (<>, <>) DECLARE_COMPARISON_OPERATORS ( >, <) DECLARE_COMPARISON_OPERATORS ( <, >) DECLARE_COMPARISON_OPERATORS (>=, <=) DECLARE_COMPARISON_OPERATORS (<=, >=) function AbsReal (const x: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init (c^); mpf_abs (c^, x) end; function AbsRealVal (x: TRealValue) = c: TRealValue; attribute (inline, unused); begin mpf_abs (x^, x^); c := x end; function SqrReal (const x: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init (c^); mpf_mul (c^, x, x) end; function SqrRealVal (x: TRealValue) = c: TRealValue; attribute (inline, unused); begin mpf_mul (x^, x^, x^); c := x end; function SqrtReal (const x: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init (c^); mpf_sqrt (c^, x) end; function SqrtRealVal (x: TRealValue) = c: TRealValue; attribute (inline, unused); begin mpf_sqrt (x^, x^); c := x end; function ExpReal (const x: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init (c^); mpf_exp (c^, x) end; function ExpRealVal (x: TRealValue): TRealValue; attribute (inline, unused); begin ExpRealVal := ExpReal (x^); RealValueDone (x) end; function LnReal (const Src: TRealPar) = c: TRealValue; attribute (inline, unused); begin New (c); mpf_init(c^); mpf_ln (c^, Src) end; function LnRealVal (x: TRealValue): TRealValue; attribute (inline, unused); begin LnRealVal := LnReal (x^); RealValueDone (x) end; {$define WRITE_REAL_ROUTINE(WRITE, DEST) var Exp: mp_exp_t; p, q: CString; Sign: String (1); begin p := mpf_get_str (nil, Exp, 10, MaxDigits, v); if p[0] = '-'then begin Sign := '-'; q := p + 1 end else begin Sign := ''; q := p end; WRITE (DEST, Sign, '0.', q, 'e', Exp); Dispose (p) end;} procedure WriteStrReal (var s: String; const v: TRealPar; MaxDigits: Integer); attribute (unused); {$local X+} WRITE_REAL_ROUTINE (WriteStr, s) {$endlocal} procedure WriteStrRealVal (var s: String; v: TRealValue; MaxDigits: Integer); attribute (unused); begin WriteStrReal (s, v^, MaxDigits); RealValueDone (v) end; procedure WriteReal (var f: Text; const v: TRealPar; MaxDigits: Integer); attribute (unused); {$local X+} WRITE_REAL_ROUTINE (Write, f) {$endlocal} procedure WriteRealVal (var f: Text; v: TRealValue; MaxDigits: Integer); attribute (unused); begin WriteReal (f, v^, MaxDigits); RealValueDone (v) end; function ReadStrReal (const s: String; var v: TRealPar; SetPrecision: Boolean): Integer; attribute (unused); var MaxNeededPrecision: MedCard; begin if SetPrecision then begin MaxNeededPrecision := Round (Length (s) * Ln (10) / Ln (2) + 2); if MaxNeededPrecision > RealPrecision then SetPrecisionReal (MaxNeededPrecision) end; RInit (v); ReadStrReal := mpf_set_str (v, s, 10) end; procedure ReadReal (var f: Text; var v: TRealPar; SetPrecision: Boolean); attribute (unused); var s, t: ^String; Size: Integer; Position: (Sign, Left, Right, ExpSign, Exp, Done); begin Size := 1024; New (s, Size); s^ := ''; while f^ in [' ', #9, #10, #13] do if EOLn (f) then ReadLn (f) else Get (f); Position := Sign; repeat if Length (s^) >= Size then begin Size := 2 * Size; New (t, Size); t^ := s^; Dispose (s); s := t end; case f^ of '-': if Position in [Sign, ExpSign] then Inc (Position) else Position := Done; '0' .. '9': if Position in [Sign, ExpSign] then Inc (Position); '.': if Position in [Sign, Left] then Position := Right else Position := Done; 'E', 'e', '@': if Position in [Left, Right] then Position := ExpSign else Position := Done; else Position := Done end; if Position <> Done then begin s^ := s^ + f^; Get (f) end until Position = Done; if ReadStrReal (s^, v, SetPrecision) <> 0 then begin WriteLn ('Invalid numeric format.'); RunError end; Dispose (s) end; {$else} type PReal = ^TReal; TReal = Real; TRealVar = TReal; TRealPar = TRealVar; TRealValue = TReal; procedure SetPrecisionReal (NewPrecision: Word); attribute (inline, unused); begin Discard (NewPrecision) { Can't change the precision of normal reals. } end; procedure InitReal (a: TRealPar); attribute (inline, unused); begin Discard (a) end; procedure DoneReal (a: TRealPar); attribute (inline, unused); begin Discard (a) end; procedure AssignReal (var a: TRealPar; b: TRealPar); attribute (inline, unused); begin a := b end; procedure AssignRealVal (var a: TRealPar; b: TRealValue); attribute (inline, unused); begin a := b end; procedure AssignRealPlainReal (var a: TRealPar; b: Real); attribute (inline, unused); begin a := b end; procedure AssignRealInteger (var a: TRealPar; b: Integer); attribute (inline, unused); begin a := b end; function PassReal (a: TRealPar): TRealPar; attribute (inline, unused); begin PassReal := a end; function PassRealVal (a: TRealValue): TRealPar; attribute (inline, unused); begin PassRealVal := a end; function Real2PlainReal (a: TRealPar): Real; attribute (inline, unused); begin Real2PlainReal := a end; function Real2PlainRealVal (a: TRealValue): Real; attribute (inline, unused); begin Real2PlainRealVal := a end; function RoundReal (a: TRealPar): LongInt; attribute (inline, unused); begin RoundReal := Round (a) end; function RoundRealVal (a: TRealValue): LongInt; attribute (inline, unused); begin RoundRealVal := Round (a) end; function AbsReal (x: TRealPar): TRealPar; attribute (inline, unused); begin AbsReal := Abs (x) end; function AbsRealVal (x: TRealValue): TRealPar; attribute (inline, unused); begin AbsRealVal := Abs (x) end; function SqrReal (x: TRealPar): TRealPar; attribute (inline, unused); begin SqrReal := Sqr (x) end; function SqrRealVal (x: TRealValue): TRealPar; attribute (inline, unused); begin SqrRealVal := Sqr (x) end; function SqrtReal (x: TRealPar): TRealPar; attribute (inline, unused); begin SqrtReal := SqRt (x) end; function SqrtRealVal (x: TRealValue): TRealPar; attribute (inline, unused); begin SqrtRealVal := SqRt (x) end; function ExpReal (x: TRealPar): TRealPar; attribute (inline, unused); begin ExpReal := Exp (x) end; function ExpRealVal (x: TRealValue): TRealPar; attribute (inline, unused); begin ExpRealVal := Exp (x) end; function LnReal (x: TRealPar): TRealPar; attribute (inline, unused); begin LnReal := Ln (x) end; function LnRealVal (x: TRealValue): TRealPar; attribute (inline, unused); begin LnRealVal := Ln (x) end; procedure WriteStrReal (var s: String; v: TRealPar; MaxDigits: Integer); attribute (inline, unused); begin if MaxDigits = 0 then Str (v, s) else Str (v : MaxDigits, s) end; procedure WriteStrRealVal (var s: String; v: TRealValue; MaxDigits: Integer); attribute (inline, unused); begin WriteStrReal (s, v, MaxDigits) end; procedure WriteReal (var f: Text; v: TRealPar; MaxDigits: Integer); attribute (inline, unused); begin if MaxDigits = 0 then Write (f, v) else Write (f, v : 0 : MaxDigits) end; procedure WriteRealVal (var f: Text; v: TRealValue; MaxDigits: Integer); attribute (inline, unused); begin WriteReal (f, v, MaxDigits) end; function ReadStrReal (const s: String; var v: TRealPar; SetPrecision: Boolean): Integer; attribute (inline, unused); var e: Integer; begin Discard (SetPrecision); Val (s, v, e); ReadStrReal := e end; procedure ReadReal (var f: Text; var v: TRealPar; SetPrecision: Boolean); attribute (inline, unused); begin Discard (SetPrecision); Read (f, v) end; {$endif}