mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-15 16:38:54 +00:00

Closes GH-215 git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@351700 c90b9560-bf6c-de11-be94-00142212c4b1
190 lines
5.8 KiB
XML
190 lines
5.8 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
<sect1 xml:id="language.types.float" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>Floating point numbers</title>
|
||
|
||
<para>
|
||
Floating point numbers (also known as "floats", "doubles", or "real numbers")
|
||
can be specified using any of the following syntaxes:
|
||
</para>
|
||
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$a = 1.234;
|
||
$b = 1.2e3;
|
||
$c = 7E-10;
|
||
$d = 1_234.567; // as of PHP 7.4.0
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
|
||
<para>
|
||
Formally as of PHP 7.4.0 (previously, underscores have not been allowed):
|
||
</para>
|
||
|
||
<informalexample>
|
||
<programlisting>
|
||
<![CDATA[
|
||
LNUM [0-9]+(_[0-9]+)*
|
||
DNUM ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*)
|
||
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
|
||
<para>
|
||
The size of a float is platform-dependent, although a maximum of approximately 1.8e308
|
||
with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE
|
||
format).
|
||
</para>
|
||
|
||
<warning xml:id="warn.float-precision">
|
||
<title>Floating point precision</title>
|
||
|
||
<para>
|
||
Floating point numbers have limited precision. Although it depends on the
|
||
system, PHP typically uses the IEEE 754 double precision format, which will
|
||
give a maximum relative error due to rounding in the order of 1.11e-16.
|
||
Non elementary arithmetic operations may give larger errors, and, of course,
|
||
error propagation must be considered when several operations are
|
||
compounded.
|
||
</para>
|
||
|
||
<para>
|
||
Additionally, rational numbers that are exactly representable as floating
|
||
point numbers in base 10, like <literal>0.1</literal> or
|
||
<literal>0.7</literal>, do not have an exact representation as floating
|
||
point numbers in base 2, which is used internally, no matter the size of
|
||
the mantissa. Hence, they cannot be converted into their internal binary
|
||
counterparts without a small loss of precision. This can lead to confusing
|
||
results: for example, <literal>floor((0.1+0.7)*10)</literal> will usually
|
||
return <literal>7</literal> instead of the expected <literal>8</literal>,
|
||
since the internal representation will be something like
|
||
<literal>7.9999999999999991118...</literal>.
|
||
</para>
|
||
|
||
<para>
|
||
So never trust floating number results to the last digit, and do not compare
|
||
floating point numbers directly for equality. If higher precision is
|
||
necessary, the <link linkend="ref.bc">arbitrary precision math functions</link>
|
||
and <link linkend="ref.gmp">gmp</link> functions are available.
|
||
</para>
|
||
|
||
<para>
|
||
For a "simple" explanation, see the <link xlink:href="&url.floating.point.guide;">floating point guide</link>
|
||
that's also titled "Why don’t my numbers add up?"
|
||
</para>
|
||
</warning>
|
||
|
||
<sect2 xml:id="language.types.float.casting">
|
||
<title>Converting to float</title>
|
||
|
||
<sect3 xml:id="language.types.float.casting.from-string">
|
||
<title>From strings</title>
|
||
|
||
<simpara>
|
||
If the string is
|
||
<link linkend="language.types.numeric-strings">numeric</link>
|
||
or leading numeric then it will resolve to the
|
||
corresponding float value, otherwise it is converted to zero
|
||
(<literal>0</literal>).
|
||
</simpara>
|
||
</sect3>
|
||
|
||
<sect3 xml:id="language.types.float.casting.from-other">
|
||
<title>From other types</title>
|
||
|
||
<para>
|
||
For values of other types, the conversion is performed by converting the
|
||
value to <type>int</type> first and then to <type>float</type>. See
|
||
<link linkend="language.types.integer.casting">Converting to integer</link>
|
||
for more information.
|
||
</para>
|
||
|
||
<note>
|
||
<para>
|
||
As certain types have undefined behavior when converting to
|
||
<type>int</type>, this is also the case when converting to
|
||
<type>float</type>.
|
||
</para>
|
||
</note>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.types.float.comparison">
|
||
<title>Comparing floats</title>
|
||
|
||
<para>
|
||
As noted in the warning above, testing floating point values for equality is
|
||
problematic, due to the way that they are represented internally. However,
|
||
there are ways to make comparisons of floating point values that work around
|
||
these limitations.
|
||
</para>
|
||
|
||
<para>
|
||
To test floating point values for equality, an upper bound on the relative
|
||
error due to rounding is used. This value is known as the machine epsilon,
|
||
or unit roundoff, and is the smallest acceptable difference in calculations.
|
||
</para>
|
||
|
||
<informalexample>
|
||
<simpara>
|
||
<varname>$a</varname> and <varname>$b</varname> are equal to 5 digits of
|
||
precision.
|
||
</simpara>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$a = 1.23456789;
|
||
$b = 1.23456780;
|
||
$epsilon = 0.00001;
|
||
|
||
if(abs($a-$b) < $epsilon) {
|
||
echo "true";
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.types.float.nan">
|
||
<title>NaN</title>
|
||
<para>
|
||
Some numeric operations can result in a value represented by the constant
|
||
<constant>NAN</constant>. This result represents an undefined or
|
||
unrepresentable value in floating-point calculations. Any loose or strict
|
||
comparisons of this value against any other value, including itself, but except &true;, will
|
||
have a result of &false;.
|
||
</para>
|
||
<para>
|
||
Because <constant>NAN</constant> represents any number of different values,
|
||
<constant>NAN</constant> should not be compared to other values, including
|
||
itself, and instead should be checked for using <function>is_nan</function>.
|
||
</para>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|