Contenuto principale

vpa

Variable-precision arithmetic (arbitrary-precision arithmetic)

Description

yVpa = vpa(y) uses variable-precision arithmetic (with arbitrary-precision floating-point numbers) to evaluate each element of the input y to at least d significant digits, where d is the value of the digits function. The default value of digits is 32.

example

yVpa = vpa(y,d) uses at least d significant digits instead of the value of digits.

example

yVpa = vpa(___,BoostPrecision=tf), when y is double precision, specifies whether to increase the precision of y when converting it to a symbolic number with variable precision. By default, when you pass a double-precision input to vpa, the function attempts to increase the precision during conversion. To preserve the original bit pattern of the double-precision input, set BoostPrecision to false. You can use this option in addition to any of the input argument combinations in previous syntaxes. (since R2026a)

example

Examples

collapse all

Evaluate symbolic inputs using variable-precision floating-point arithmetic. By default, vpa calculates values to 32 significant digits.

Evaluate π to 32 significant digits.

p = sym(pi);
pVpa = vpa(p)
pVpa = 3.1415926535897932384626433832795

Evaluate a symbolic expression.

syms x
a = sym(1/3);
f = a*sin(2*p*x);
fVpa = vpa(f)
fVpa = 0.33333333333333333333333333333333sin(6.283185307179586476925286766559x)

Evaluate elements of symbolic vectors or matrices using variable-precision arithmetic.

V = [x/p a^3];
VVpa = vpa(V)
VVpa = (0.31830988618379067153776752674503x0.037037037037037037037037037037037)
M = [sin(p) cos(p/5); exp(p*x) x/log(p)];
MVpa = vpa(M)
MVpa = 

(00.80901699437494742410229341718282e3.1415926535897932384626433832795x0.87356852683023186835397746476334x)

By default, vpa evaluates inputs to 32 significant digits. You can change the number of significant digits by using the digits function.

Approximate the symbolic expression 100001/10001 using seven significant digits. Set the number of significant digits using digits, and save the original value of digits. The vpa function returns only five significant digits, which can mean the subsequent digits are zeros.

digitsOld = digits(7);
y = sym(100001)/10001;
yVpa = vpa(y)
yVpa = 9.9991

Check if the subsequent digits are zeros by using a higher precision value of 25. The result shows that the subsequent digits are in fact zeros that are part of a repeating decimal.

digits(25)
yVpa = vpa(y)
yVpa = 9.999100089991000899910009

Alternatively, to override digits for a single vpa call, change the precision by specifying the second argument.

Find π to 100 significant digits by specifying the second argument.

pVpa = vpa(sym(pi),100)
pVpa = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

Restore the original precision value for further calculations.

digits(digitsOld)

While symbolic results are exact, they might not be in a convenient form. You can use vpa to numerically approximate exact symbolic results.

Solve a high-degree polynomial for its roots using solve. The solve function cannot symbolically solve the high-degree polynomial and represents the roots using root.

syms x
y = solve(x^4 - x + 1, x)
y = 

(root(z4-z+1,z,1)root(z4-z+1,z,2)root(z4-z+1,z,3)root(z4-z+1,z,4))

Use vpa to numerically approximate the roots.

yVpa = vpa(y)
yVpa = 

(0.72713608449119683997667565867496-0.43001428832971577641651985839602i0.72713608449119683997667565867496+0.43001428832971577641651985839602i-0.72713608449119683997667565867496-0.93409928946052943963903028710582i-0.72713608449119683997667565867496+0.93409928946052943963903028710582i)

The digits function specifies the minimum number of significant digits to use in variable-precision arithmetic. Alternatively, you can use the vpa(y,d) syntax to convert an input y to at least d significant digits. Internally, vpa uses more digits than specified. These additional digits are called guard digits because they guard against round-off errors in subsequent calculations.

Approximate π using four significant digits.

pi_4digits = vpa(sym(pi),4)
pi_4digits = 3.142

Next, use the previous result to approximate π to six significant digits. The result shows that the vpa function used more than four digits during the initial conversion of π, demonstrating the use of guard digits.

pi_6digits = vpa(pi_4digits,6)
pi_6digits = 3.14159

The double-precision format stores a number using 64 bits of memory, resulting in limited numerical precision. When you call vpa on a double-precision input, vpa generally cannot restore any lost precision beyond the typical 16 significant digits of the double-precision representation, even though vpa returns more digits than the original double-precision value. However, vpa uses an algorithm that can recognize and increase the precision of operations of the form pq, pπq, (pq)12, 2q, and 10q, where p and q are modest-sized integers.

First, demonstrate that vpa cannot increase the precision for a double-precision evaluation that involves the log function. Call vpa on a double-precision result and the same symbolic result.

yDouble = log(3);
ySym = log(sym(3));
yDoubleToVpa = vpa(yDouble)
yDoubleToVpa = 1.0986122886681097821082175869378
ySymToVpa = vpa(ySym)
ySymToVpa = 1.0986122886681096913952452369225
d = yDoubleToVpa - ySymToVpa
d = 0.000000000000000090712972350015300422166375941649

As expected, the double-precision result differs from the symbolic result after the 16th decimal place.

Demonstrate that vpa increases the precision for expressions of the form pq, pπq, (pq)12, 2q, and 10q, where p and q are modest-sized integers, by finding the difference between the vpa call on the double-precision result and on the exact symbolic result. The differences are 0.0 showing that vpa restores lost precision for the double-precision input.

d = vpa(1/3) - vpa(1/sym(3))
d = 0.0
d = vpa(pi) - vpa(sym(pi))
d = 0.0
d = vpa(1/sqrt(2)) - vpa(1/sqrt(sym(2)))
d = 0.0
d = vpa(2^66) - vpa(2^sym(66))
d = 0.0
d = vpa(10^25) - vpa(10^sym(25))
d = 0.0

Starting in R2026a, you can choose to use vpa without increasing the precision for double-precision expressions of the form pq, pπq, (pq)12, 2q, and 10q by specifying the BoostPrecision option as false. For example, convert the double-precision value of 1/3 to variable precision by preserving the bit pattern of the double representation, without restoring any lost precision after the 16th decimal place. The result is not equal to calling vpa on the exact symbolic result.

yDoubleToVpa = vpa(1/3,BoostPrecision=false)
yDoubleToVpa = 0.33333333333333331482961625624739
ySymToVpa = vpa(1/sym(3))
ySymToVpa = 0.33333333333333333333333333333333
d = yDoubleToVpa - ySymToVpa
d = -0.000000000000000018503717077085942340393891746679

When you perform operations on numbers with different precision, the results can contain hidden errors.

For example, evaluate 1/10 with 6-digit precision and with 5-digit precision.

a = vpa(1/10,6)
a = 0.1
b = vpa(1/10,5)
b = 0.1

Although the displayed values of a and b look the same, these two variables are not exactly equal because they store different digits beyond the 6th and 5th significant digits, respectively. Check their equality by computing the difference a - b.

roundoff = a - b
roundoff = 0.0000000000000053290705182007513940334320068359
digits
 
Digits = 32
 

The result of a - b is not zero. The reason is that a is accurate to 6 digits and b is accurate to 5 digits, but the subtraction uses the default 32 digits of precision set by digits.

To show the different values of a and b, convert their original values to 32 significant digits.

a_32digits = vpa(a,32)
a_32digits = 0.099999999999999644728632119949907
b_32digits = vpa(b,32)
b_32digits = 0.099999999999994315658113919198513

Compute the difference between these converted values.

roundoff = a_32digits - b_32digits
roundoff = 0.0000000000000053290705182007513940334320068359

Approximate the number 111111111111111111 with 32 significant digits by using vpa. The result is not accurate after the 16th digit because when you enter a number in MATLAB, it is converted to the nearest representable double-precision value, which might not be exactly equal to the number you typed.

xVpa = vpa(111111111111111111)
xVpa = 111111111111111104.0

To accurately represent the number, use string input. Here, vpa approximates the number 111111111111111111 accurately to 32 significant digits.

xVpa = vpa("111111111111111111")
xVpa = 111111111111111111.0

Since R2022b

Create a symbolic expression S that represents sin([ππ2π2π3]X), where X is a 2-by-1 symbolic matrix variable.

syms X [2 1] matrix
S = sin(hilb(2)*pi*X)
S = 

sin(Σ1X)where  Σ1=(ππ2π2π3)

Evaluate the expression using variable-precision arithmetic.

SVpa = vpa(S)
SVpa = 

(sin(3.1415926535897932384626433832795X1+1.5707963267948966192313216916398X2)sin(1.5707963267948966192313216916398X1+1.0471975511965977461542144610932X2))

Since R2026a

When converting a double-precision number to a symbolic number, vpa by default attempts to increase the precision, which can lead to unintended results. Specifically, vpa might interpret the least significant digits of double-precision numbers as round-off errors.

For example, consider two adjacent double-precision numbers: 1 and the next larger double-precision number after 1.

x = 1;
y = 1 + eps;

If you convert these two numbers using vpa, the converted numbers are equal and their difference is zero. In this case, the least significant bit of y is not preserved because vpa treats it as a round-off error.

d = vpa(y) - vpa(x)
d = 0.0

However, in double-precision representation, these two numbers have different bit patterns, which can be observed in hexadecimal format.

x_hexStr = num2hex(x)
x_hexStr = 
'3ff0000000000000'
y_hexStr = num2hex(y)
y_hexStr = 
'3ff0000000000001'

To preserve the bit pattern when converting double-precision inputs with vpa, specify the BoostPrecision option as false. Now, the difference between the converted numbers is closer to eps.

d = vpa(y,BoostPrecision=false) - vpa(x,BoostPrecision=false)
d = 0.00000000000000022204460492503130808472633361816
format longE
eps
ans = 
     2.220446049250313e-16

Although vpa preserves the bit pattern of the double numbers, it still uses the default 32 significant digits and attempts to fill in the additional digits beyond the significant digits of the double numbers. To make the difference between the converted numbers equal to eps, you can set the number of significant digits to 16 for the vpa operations.

digits(16)
d = vpa(y,BoostPrecision=false) - vpa(x,BoostPrecision=false)
d = 0.0000000000000002220446049250313

Finally, restore the precision used by vpa to 32 digits and the output display format to the default.

digits(32)
format default

Input Arguments

collapse all

Input to evaluate, specified as a scalar, vector, matrix, or multidimensional array of numeric values or strings, or as a symbolic number, vector, matrix, multidimensional array, expression, function, character vector, or matrix variable.

  • When you enter a number in MATLAB®, it is converted to the nearest representable double-precision value, which might not be exactly equal to the number you typed. To accurately represent the number, you can specify y as a string input.

  • If you specify y as a single-precision number, vpa first converts it to double-precision before converting the number to variable-precision.

Data Types: double | single | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | char | string | sym | symfun | symmatrix
Complex Number Support: Yes

Number of significant digits, specified as a positive integer scalar. If you do not specify this argument, then the digits function determines the number of significant digits used by vpa.

If d is not an integer, vpa rounds it to the nearest integer using the round function.

Since R2026a

Option to increase the precision for double-precision input, specified as a numeric or logical 1 (true) or 0 (false). By default, when y is double precision, vpa attempts to increase the precision of y when converting it to a symbolic number with variable precision. To preserve the original bit pattern of the double-precision input, specify this argument as false.

If y is not double precision, this argument has no effect.

Output Arguments

collapse all

Variable-precision output, returned as a symbolic number, vector, matrix, multidimensional array, expression, or function.

  • For almost all input data types (such as sym, symmatrix, string, double, single, int64, and so on), vpa returns the output as data type sym.

  • If the input is a symbolic function of type symfun, then vpa returns the output as data type symfun. For example, syms f(x); f(x) = pi*x; g = vpa(f) returns the output g as type symfun.

  • If the input is an evaluated symbolic function of type sym, such as g = vpa(f(x)), then vpa returns the output as data type sym.

Data Types: sym | symfun

Tips

  • vpa does not convert fractions in the exponent to floating point. For example, vpa(a^sym(2/5)) returns a^(2/5).

  • vpa internally uses more digits than the number of digits specified by digits. These extra digits guard against round-off errors in subsequent calculations. For an example, see vpa Uses Guard Digits to Maintain Precision.

  • When you call vpa on a numeric input, such as 1/3, 2^(-5), or sin(pi/4), the expression is first evaluated as a double-precision number, providing 64 bits or approximately 16 digits of precision. vpa then increases the precision to the specified number of significant digits. For more accurate results, define symbolic inputs instead by using sym. For example, to approximate exp(1) to 32 significant digits, use vpa(exp(sym(1))).

  • By default, vpa increases the precision for numeric inputs that match the forms p/q, pπ/q, (p/q)1/2, 2q, and 10q, where p and q are modest-sized integers. For more information, see Maintain Precision of Common Double-Precision Inputs.

  • Variable-precision arithmetic is different from IEEE® Floating-Point Standard 754 in these ways:

    • Inside computations, division by zero throws an error.

    • The exponent range is larger than in any predefined IEEE mode. vpa underflows below approximately 10^(-323228496).

    • Denormalized numbers are not implemented.

    • Zeros are not signed.

    • The number of binary digits in the mantissa of a result might differ between variable-precision arithmetic and IEEE predefined types.

    • There is only one NaN representation. No distinction is made between quiet and signaling NaN.

    • No floating-point number exceptions are available.

Version History

Introduced before R2006a

expand all