Arithmetic operations with scalars and iterables#
fadd: Addition using a custom precision and rounding mode#
- ctx.fadd(x, y, **kwargs)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [697].!!! There is no special code for fadd except mp !!!
!!! Add special code for dp, gp, ap !!!
!!! fp and iv still missing !!!
Adds the numbers x and y, giving a floating-point result, optionally using a custom precision and rounding mode.
The default precision is the working precision of the context. You can specify a custom precision in bits by passing the prec keyword argument, or by providing an equivalent decimal precision with the dps keyword argument. If the precision is set to
+inf, or if the flag exact=True is passed, an exact addition with no rounding is performed. Changing the precision has no effect for the fp context.For the mp, dp, gp, and ap (in point mode only) contexts: when the precision is finite, the optional rounding keyword argument specifies the direction of rounding. Valid options are
'n'for nearest (default),'f'for floor,'c'for ceiling,'d'for down,'u'for up.Examples
Using
fadd()with precision and rounding control:>>> from mpfunlab import fp, mp, iv, dp, gp, ap >>> mp.fadd(2, 1e-20) mpf('2.0') >>> mp.nprint(mp.fadd(2, 1e-20, prec=100), 25) 2.00000000000000000001 >>> mp.nprint(mp.fadd(2, 1e-20, dps=15), 25) 2.0 >>> mp.nprint(mp.fadd(2, 1e-20, dps=25), 25) 2.00000000000000000001 >>> mp.nprint(mp.fadd(2, 1e-20, exact=True), 25) 2.00000000000000000001 >>> gp.dps = 15; gp.pretty = False >>> gp.fadd(2, 1e-20) mpfr('2.0') >>> gp.nprint(gp.fadd(2, 1e-20, prec=100), 25) 2.000000000000000000000000E+00 >>> gp.nprint(gp.fadd(2, 1e-20, dps=15), 25) 2.000000000000000000000000E+00 >>> gp.nprint(gp.fadd(2, 1e-20, dps=25), 25) 2.000000000000000000000000E+00 >>> gp.nprint(gp.fadd(2, 1e-20, exact=True), 25) 2.000000000000000000000000E+00 >>> dp.dps = 15; dp.pretty = False >>> dp.fadd(2, 1e-20) Decimal('2.00000000000000') >>> dp.nprint(dp.fadd(2, 1e-20, prec=100), 25) 2.000000000000000000000000E+0 >>> dp.dps=100 >>> dp.mpf(2) + dp.mpf('1e-20') Decimal('2.00000000000000000001') >>> dp.nprint(dp.fadd(2, 1e-20, dps=15), 25) 2.000000000000000000010000E+0 >>> dp.nprint(dp.fadd(2, 1e-20, dps=25), 25) 2.000000000000000000010000E+0 >>> dp.nprint(dp.fadd(2, 1e-20, exact=True), 25) 2.000000000000000000010000E+0 >>> ap.dps = 15; ap.pretty = False >>> ap.fadd(2, 1e-20) arb3_t('[2.00000000000000 +/- 4.45e-16]') >>> ap.fadd(2, 1e-20, rounding='u') arb3_t('[2.00000000000000 +/- 4.45e-16]') >>> ap.nprint(ap.fadd(2, 1e-20, prec=100), 25) # nprint not properly implemented >>> ap.dps=25 >>> ap.mpf(2) + ap.mpf('1e-20') arb3_t('[2.000000000000000000010000 +/- 5.85e-26]') >>> ap.nprint(ap.fadd(2, 1e-20, dps=15), 25) # nprint not properly implemented >>> ap.nprint(ap.fadd(2, 1e-20, dps=25), 25) # nprint not properly implemented >>> ap.nprint(ap.fadd(2, 1e-20, exact=True), 25) # nprint not properly implemented
This is the current state of affairs in iv:
>>> iv.dps = 15; iv.pretty = False >>> iv.fadd(2, 1e-20) mpi('2.0', '2.0000000000000004') >>> iv.nprint(iv.fadd(2, 1e-20, prec=100), 25) [2.0, 2.00000000000000044408921]# nprint not properly implemented >>> iv.nprint(iv.fadd(2, 1e-20, dps=15), 25) [2.0, 2.00000000000000044408921]# nprint not properly implemented >>> iv.nprint(iv.fadd(2, 1e-20, dps=25), 25) [2.0, 2.00000000000000044408921]# nprint not properly implemented >>> iv.nprint(iv.fadd(2, 1e-20, exact=True), 25) [2.0, 2.00000000000000044408921]# nprint not properly implemented
TODO: Another ap example in floating point mode
See also: https://docs.python.org/3/tutorial/floatingpoint.html#tut-fp-issues.
Exact addition avoids cancellation errors, enforcing familiar laws of numbers such as \(x+y-x = y\), which don’t hold in floating-point arithmetic with finite precision:
>>> x, y = mp.mpf(2), mp.mpf('1e-1000') >>> print(x + y - x) 0.0 >>> print(mp.fadd(x, y, prec=inf) - x) 1.0e-1000 >>> print(mp.fadd(x, y, exact=True) - x) 1.0e-1000
Exact addition can be inefficient and may be impossible to perform with large magnitude differences:
>>> fadd(1, '1e-100000000000000000000', prec=inf) Traceback (most recent call last): ... OverflowError: the exact result does not fit in memory
fsub: Subtraction using a custom precision and rounding mode#
- ctx.fsub(x, y, **kwargs)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [713].Subtracts the numbers x and y, giving a floating-point result, optionally using a custom precision and rounding mode.
See the documentation of
fadd()for a detailed description of how to specify precision and rounding.Examples
Using
fsub()with precision and rounding control:>>> from mpmath import * >>> mp.dps = 15; mp.pretty = False >>> fsub(2, 1e-20) mpf('2.0') >>> fsub(2, 1e-20, rounding='d') mpf('1.9999999999999998') >>> nprint(fsub(2, 1e-20, prec=100), 25) 1.99999999999999999999 >>> nprint(fsub(2, 1e-20, dps=15), 25) 2.0 >>> nprint(fsub(2, 1e-20, dps=25), 25) 1.99999999999999999999 >>> nprint(fsub(2, 1e-20, exact=True), 25) 1.99999999999999999999
Exact subtraction avoids cancellation errors, enforcing familiar laws of numbers such as \(x-y+y = x\), which don’t hold in floating-point arithmetic with finite precision:
>>> x, y = mpf(2), mpf('1e1000') >>> print(x - y + y) 0.0 >>> print(fsub(x, y, prec=inf) + y) 2.0 >>> print(fsub(x, y, exact=True) + y) 2.0
Exact subtraction can be inefficient and may be impossible to perform with large magnitude differences:
>>> fsub(1, '1e-100000000000000000000', prec=inf) Traceback (most recent call last): ... OverflowError: the exact result does not fit in memory
fneg: Negation of a number using a custom precision and rounding mode#
- ctx.fneg(x, **kwargs)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [708].!!! NEEDS TO DESCRIBE PARAMETERS !!!!
Negates the number x, giving a floating-point result, optionally using a custom precision and rounding mode.
See the documentation of
fadd()for a detailed description of how to specify precision and rounding.Examples
An mpmath number is returned:
>>> from mpmath import * >>> mp.dps = 15; mp.pretty = False >>> fneg(2.5) mpf('-2.5') >>> fneg(-5+2j) mpc(real='5.0', imag='-2.0')
Precise control over rounding is possible:
>>> x = fadd(2, 1e-100, exact=True) >>> fneg(x) mpf('-2.0') >>> fneg(x, rounding='f') mpf('-2.0000000000000004')
Negating with and without roundoff:
>>> n = 200000000000000000000001 >>> print(int(-mpf(n))) -200000000000000016777216 >>> print(int(fneg(n))) -200000000000000016777216 >>> print(int(fneg(n, prec=log(n,2)+1))) -200000000000000000000001 >>> print(int(fneg(n, dps=log(n,10)+1))) -200000000000000000000001 >>> print(int(fneg(n, prec=inf))) -200000000000000000000001 >>> print(int(fneg(n, dps=inf))) -200000000000000000000001 >>> print(int(fneg(n, exact=True))) -200000000000000000000001
fmul: Multiplication using a custom precision and rounding mode#
- ctx.fmul(x, y, **kwargs)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [707].Multiplies the numbers x and y, giving a floating-point result, optionally using a custom precision and rounding mode.
See the documentation of
fadd()for a detailed description of how to specify precision and rounding.Examples
The result is an mpmath number:
>>> from mpmath import * >>> mp.dps = 15; mp.pretty = False >>> fmul(2, 5.0) mpf('10.0') >>> fmul(0.5j, 0.5) mpc(real='0.0', imag='0.25')
Avoiding roundoff:
>>> x, y = 10**10+1, 10**15+1 >>> print(x*y) 10000000001000010000000001 >>> print(mpf(x) * mpf(y)) 1.0000000001e+25 >>> print(int(mpf(x) * mpf(y))) 10000000001000011026399232 >>> print(int(fmul(x, y))) 10000000001000011026399232 >>> print(int(fmul(x, y, dps=25))) 10000000001000010000000001 >>> print(int(fmul(x, y, exact=True))) 10000000001000010000000001
Exact multiplication with complex numbers can be inefficient and may be impossible to perform with large magnitude differences between real and imaginary parts:
>>> x = 1+2j >>> y = mpc(2, '1e-100000000000000000000') >>> fmul(x, y) mpc(real='2.0', imag='4.0') >>> fmul(x, y, rounding='u') mpc(real='2.0', imag='4.0000000000000009') >>> fmul(x, y, exact=True) Traceback (most recent call last): ... OverflowError: the exact result does not fit in memory
fdiv: Division using a custom precision and rounding mode#
- ctx.fdiv(x, y, **kwargs)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [702].Divides the numbers x and y, giving a floating-point result, optionally using a custom precision and rounding mode.
See the documentation of
fadd()for a detailed description of how to specify precision and rounding.Examples
The result is an mpmath number:
>>> from mpmath import * >>> mp.dps = 15; mp.pretty = False >>> fdiv(3, 2) mpf('1.5') >>> fdiv(2, 3) mpf('0.66666666666666663') >>> fdiv(2+4j, 0.5) mpc(real='4.0', imag='8.0')
The rounding direction and precision can be controlled:
>>> fdiv(2, 3, dps=3) # Should be accurate to at least 3 digits mpf('0.6666259765625') >>> fdiv(2, 3, rounding='d') mpf('0.66666666666666663') >>> fdiv(2, 3, prec=60) mpf('0.66666666666666667') >>> fdiv(2, 3, rounding='u') mpf('0.66666666666666674')
Checking the error of a division by performing it at higher precision:
>>> fdiv(2, 3) - fdiv(2, 3, prec=100) mpf('-3.7007434154172148e-17')
Unlike
fadd(),fmul(), etc., exact division is not allowed since the quotient of two floating-point numbers generally does not have an exact floating-point representation. (In the future this might be changed to allow the case where the division is actually exact.)>>> fdiv(2, 3, exact=True) Traceback (most recent call last): ... ValueError: division is not an exact operation
fsum: Sum of a finite number of terms#
- ctx.fsum(terms, absolute=False, squared=False)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [714].Calculates a sum containing a finite number of terms . With squared=True each term is squared, and with absolute=True the absolute value of each term is used.
>>> from mpfunlab import fp, mp, iv, dp, gp, ap >>> A = [1, 2, 0.5, 7] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fsum(A)), end=', ') 10.5, mpf('10.5'), mpi('10.5', '10.5'), Decimal('10.5'), mpfr('10.5'), arb3_t('10.5'),
fprod: Product of a finite number of factors#
- ctx.fprod(factors)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [710].Calculates a product containing a finite number of factors (for infinite products, see
nprod()).The factors will be converted to mpmath numbers.
>>> from mpfunlab import fp, mp, iv, dp, gp, ap >>> A = [1, 2, 0.5, 7] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fprod(A)), end=', ') 7.0, mpf('7.0'), mpi('7.0', '7.0'), Decimal('7.0'), mpfr('7.0'), arb3_t('7.0'), >>> A = [1001, 2003, 0.5, 70005] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fprod(A))) 70180117507.5 mpf('70180117507.5') mpi('70180117507.5', '70180117507.5') Decimal('70180117507.5') mpfr('70180117507.5') arb3_t('70180117507.5')
fdot: Dot product#
- ctx.fdot(A, B=None, conjugate=False)#
where
ctxisfpm,mpm,ipm,dec,gmporapm. See also Mpmath [703].!!! conjugate not working with iv !!!
Computes the dot product of the iterables \(A\) and \(B\),
\[\sum_{k=0} A_k B_k.\]Alternatively,
fdot()accepts a single iterable of pairs. In other words,fdot(A,B)andfdot(zip(A,B))are equivalent. The elements are automatically converted to mpmath numbers.With
conjugate=True, the elements in the second vector will be conjugated:\[\sum_{k=0} A_k \overline{B_k}\]Examples
>>> from mpfunlab import fp, mp, iv, dp, gp, ap >>> A = [2, 1.5, 3]; B = [1, -1, 2] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fdot(A, B)), end=', ') 6.5, mpf('6.5'), mpi('6.5', '6.5'), Decimal('6.5'), mpfr('6.5'), arb3_t('6.5'), >>> C = list(zip(A, B)); print(C) [(2, 1), (1.5, -1), (3, 2)] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fdot(C)), end=', ') 6.5, mpf('6.5'), mpi('6.5', '6.5'), Decimal('6.5'), mpfr('6.5'), arb3_t('6.5'), >>> A = [2, 1.5, 3j]; B = [1+1j, 3, -1-1j] >>> for ctx in [fp, mp, iv, dp, gp, ap]: ctx.dps = 15; print(repr(ctx.fdot(A, B))) (9.5-1j) mpc(real='9.5', imag='-1.0') iv.mpc(mpi('9.5', '9.5'), mpi('-1.0', '-1.0')) DecCplx('9.50 - 1.0j') mpc('9.5-1.0j') acb3_t('9.5 - 1.0j') >>> A = [2, 1.5, 3j]; B = [1+1j, 3, -1-1j] >>> for ctx in [fp, mp, dp, gp, ap]: ... ctx.dps = 15; print(repr(ctx.fdot(A, B, conjugate=True))) (3.5-5j) mpc(real='3.5', imag='-5.0') DecCplx('3.50 - 5.0j') mpc('3.5-5.0j') acb3_t('3.5 - 5.0j') >>> x = ap.mpf(2); x >>> c = 3+4j; c >>> x + c