PHP Floats

Ma Mariya Vinciya Updated 17 Oct 2026
11 min read ·Lesson 55 of 102
In this post

What Is a Float? In simple terms: A float is a number with a decimal point, such as 3.14 , 0.5 , or -12.75 . Floats are used for measurements, percentages, ratios, scientific values, and averages. Tec

What Is a Float?

In simple terms: A float is a number with a decimal point, such as 3.14, 0.5, or -12.75. Floats are used for measurements, percentages, ratios, scientific values, and averages.

Technically: PHP's float type (also called double or floating-point number) is a 64-bit IEEE 754 double-precision number. It stores a value in binary as a sign, an exponent, and a significand, which gives it a huge range — but only about 15–17 significant decimal digits of precision.

Why Floats Need Special Care

Floats are approximations. Most decimal fractions — 0.1, 0.2, 0.3 — cannot be represented exactly in binary, just as 1/3 cannot be written exactly in decimal (0.3333…). The small differences are usually invisible but cause real bugs in comparisons, totals, and money calculations. Understanding why prevents those bugs.


Writing Floats

Example

<?php
$price = 499.99;
$negative = -0.75;
$scientific = 1.5e3;     // 1.5 × 10³
$small = 2.5e-4;         // 2.5 × 10⁻⁴
$withUnderscores = 1_234.567_8;  // PHP 7.4+
$fromDivision = 7 / 2;

var_dump($price, $negative, $scientific, $small, $withUnderscores, $fromDivision);

Output

float(499.99)
float(-0.75)
float(1500)
float(0.00025)
float(1234.5678)
float(3.5)

How It Works

  • A literal with a decimal point or an exponent (e / E) is a float, even if its value is whole: 1.5e3 is float(1500), not an integer.
  • Exponential notation is convenient for very large or very small values.
  • Division produces a float whenever the result is not a whole number.

The Precision Problem

Example

<?php
$sum = 0.1 + 0.2;

echo $sum . "\n";
var_dump($sum);
var_dump($sum == 0.3);

Output

0.3
float(0.30000000000000004)
bool(false)

Why This Happens

  1. 0.1 is stored as the closest binary value: 0.1000000000000000055511151231257827….
  2. 0.2 is stored as 0.2000000000000000111022302462515654….
  3. Their sum is slightly larger than the binary value closest to 0.3, so the comparison with 0.3 is false.

You can see the stored approximation by printing more digits:

<?php
printf("%.20f\n", 0.1);

Output

0.10000000000000000555

Why echo and var_dump() Show Different Values

PHP uses two configuration settings to convert floats to text:

SettingDefaultUsed ByBehavior
precision14echo, print, string conversionRounds to 14 significant digits, hiding tiny errors
serialize_precision-1var_dump(), var_export(), json_encode(), serialize()Shows the shortest representation that converts back to the exact same float

echo rounds 0.30000000000000004 to 14 digits and prints 0.3, which makes the value look correct. var_dump() shows the real stored value. When debugging float problems, always use var_dump().

Errors Accumulate

<?php
$total = 0.0;

for ($i = 0; $i < 10; $i++) {
    $total += 0.1;
}

echo $total . "\n";
var_dump($total);
var_dump($total == 1.0);

Output

1
float(0.9999999999999999)
bool(false)

Adding 0.1 ten times does not give exactly 1.0. Repeated operations — summing invoice lines, applying percentages in a loop — accumulate these small errors.


Float Limits and Constants

<?php
var_dump(PHP_FLOAT_EPSILON);
var_dump(PHP_FLOAT_MAX);
var_dump(PHP_FLOAT_MIN);
var_dump(PHP_FLOAT_DIG);

Output

float(2.220446049250313E-16)
float(1.7976931348623157E+308)
float(2.2250738585072014E-308)
int(15)
ConstantMeaning
PHP_FLOAT_EPSILONThe smallest difference between 1.0 and the next larger float
PHP_FLOAT_MAXThe largest representable float
PHP_FLOAT_MINThe smallest positive normalized float (not the most negative value — that is -PHP_FLOAT_MAX)
PHP_FLOAT_DIGNumber of decimal digits that are always preserved when a decimal value is stored as a float and printed back

Large Floats in Output

<?php
echo 1e20 . "\n";
echo 0.00001 . "\n";
echo 123456789012345678.0 . "\n";

Output

1.0E+20
1.0E-5
1.2345678901235E+17

With the default precision of 14, very large and very small floats are printed in exponential notation. Use number_format() or sprintf() to control the display.


Comparing Floats Safely

Because exact equality is unreliable, compare floats within a tolerance.

Example

<?php
function floatsEqual(float $a, float $b, float $relativeTolerance = 1e-9): bool
{
    if ($a === $b) {
        return true;
    }

    $difference = abs($a - $b);
    $largest = max(abs($a), abs($b));

    return $difference <= $largest * $relativeTolerance;
}

var_dump(0.1 + 0.2 == 0.3);
var_dump(floatsEqual(0.1 + 0.2, 0.3));
var_dump(floatsEqual(1000000.1 + 0.2, 1000000.3));
var_dump(floatsEqual(1.0, 1.1));

Output

bool(false)
bool(true)
bool(true)
bool(false)

How It Works

  • $a === $b handles exact matches immediately (including 0.0 === 0.0).
  • The difference is compared to a small fraction of the larger value's magnitude. A relative tolerance works for both small numbers (0.3) and large numbers (1000000.3), whereas a fixed tolerance such as PHP_FLOAT_EPSILON is too strict for large values.
  • Choose the tolerance based on your domain. For measurements in centimeters, a tolerance of 0.001 (absolute) may be appropriate; for scientific calculations, a relative tolerance like 1e-9 is common.

Comparing After Rounding

When values represent amounts with a known number of decimals, rounding before comparing is simple and clear:

<?php
var_dump(round(0.1 + 0.2, 2) === round(0.3, 2));

Output

bool(true)

Rounding Functions

FunctionBehaviorExampleResult
round($n)Nearest integer value (halves away from zero)round(2.5)3.0
round($n, $precision)Round to decimal placesround(3.14159, 2)3.14
round($n, -$digits)Round to tens, hundreds, …round(1234.5678, -2)1200.0
floor($n)Round down (toward negative infinity)floor(-2.7)-3.0
ceil($n)Round up (toward positive infinity)ceil(-2.1)-2.0
(int) $nTruncate toward zero(int) -2.7-2

Example

<?php
var_dump(round(2.5));
var_dump(round(-2.5));
var_dump(round(3.14159, 2));
var_dump(round(1234.5678, -2));
var_dump(floor(2.7), floor(-2.7));
var_dump(ceil(2.1), ceil(-2.1));
var_dump((int) 7.9, (int) -7.9);

Output

float(3)
float(-3)
float(3.14)
float(1200)
float(2)
float(-3)
float(3)
float(-2)
int(7)
int(-7)

Important Details

  • round(), floor(), and ceil() return floats, even when the value is whole. Cast with (int) when you need an integer, such as (int) ceil($items / $perPage).
  • floor() and ceil() move toward negative and positive infinity, so their behavior with negative numbers differs from simple truncation.
  • (int) does not round: (int) 7.9 is 7.

Rounding Modes

The third argument of round() selects how halves (.5) are handled:

<?php
foreach ([2.5, 3.5] as $n) {
    printf(
        "%.1f: HALF_UP=%d HALF_DOWN=%d HALF_EVEN=%d HALF_ODD=%d\n",
        $n,
        round($n, 0, PHP_ROUND_HALF_UP),
        round($n, 0, PHP_ROUND_HALF_DOWN),
        round($n, 0, PHP_ROUND_HALF_EVEN),
        round($n, 0, PHP_ROUND_HALF_ODD)
    );
}

Output

2.5: HALF_UP=3 HALF_DOWN=2 HALF_EVEN=2 HALF_ODD=3
3.5: HALF_UP=4 HALF_DOWN=3 HALF_EVEN=4 HALF_ODD=3
  • PHP_ROUND_HALF_UP (default) rounds halves away from zero.
  • PHP_ROUND_HALF_EVEN ("banker's rounding") rounds halves to the nearest even number. It reduces systematic bias when many values are rounded and summed, which is why it is used in some financial and statistical contexts.

Version note: PHP 8.4 added the RoundingMode enum (for example round(2.5, 0, RoundingMode::HalfEven)) and additional modes such as rounding toward zero or away from zero. The PHP_ROUND_* constants continue to work.


Special Values: INF and NAN

IEEE 754 floats include special values for results that are not ordinary numbers.

<?php
var_dump(PHP_FLOAT_MAX * 2);
var_dump(fdiv(1, 0));
var_dump(fdiv(-1, 0));
var_dump(fdiv(0, 0));
var_dump(sqrt(-1));
var_dump(log(0));

Output

float(INF)
float(INF)
float(-INF)
float(NAN)
float(NAN)
float(-INF)
ValueMeaningCheck With
INF / -INFPositive or negative infinity — overflow, or division by zero with fdiv()is_infinite()
NAN"Not a Number" — an undefined result, such as 0 / 0 or the square root of a negative numberis_nan()
Normal numberNeither of the aboveis_finite()
  • The / operator throws DivisionByZeroError when dividing by zero. fdiv() (PHP 8.0+) follows IEEE 754 rules instead and returns INF, -INF, or NAN, which is sometimes needed in scientific code.
  • NAN is not equal to anything — not even itself:
<?php
$value = sqrt(-1);

var_dump($value == $value);
var_dump(is_nan($value));

Output

bool(false)
bool(true)

Always use is_nan() to detect NAN. A NAN value that enters calculations spreads silently: any arithmetic with NAN produces NAN.


Converting to and From Floats

Strings to Floats

<?php
var_dump((float) "3.75");
var_dump((float) "1.5e3");
var_dump((float) "12.5kg");
var_dump((float) "1,234.50");
var_dump((float) "abc");

Output

float(3.75)
float(1500)
float(12.5)
float(1)
float(0)

The fourth result is a common bug: "1,234.50" converts to 1.0, because conversion stops at the comma. Remove thousands separators before converting (str_replace(',', '', $input)), or use NumberFormatter::parse() for locale-aware input such as 1.234,50.

Validate decimal input with filter_var():

<?php
var_dump(filter_var("19.99", FILTER_VALIDATE_FLOAT));
var_dump(filter_var("19.99abc", FILTER_VALIDATE_FLOAT));
var_dump(filter_var("1,234.50", FILTER_VALIDATE_FLOAT, FILTER_FLAG_ALLOW_THOUSAND));

Output

float(19.99)
bool(false)
float(1234.5)

Floats to Integers

Converting a float with a fractional part to an int truncates it. Since PHP 8.1, doing this implicitly — for example, using a float as an array key — triggers a deprecation notice:

<?php
$prices = [10, 20, 30];

echo $prices[1.5];

Output

PHP Deprecated:  Implicit conversion from float 1.5 to int loses precision
20

Convert explicitly with (int), intdiv(), round(), floor(), or ceil() so that the intended behavior is visible in the code.

Float-to-String Conversion Is Locale-Independent (PHP 8.0+)

In PHP 7, if the locale was set to one that uses a comma as the decimal separator (with setlocale()), (string) 3.14 could produce "3,14". Since PHP 8.0, float-to-string conversion always uses a dot. Use number_format() or NumberFormatter to produce localized output deliberately.


Money: Do Not Use Floats

Because floats cannot represent most decimal fractions exactly, they are unsuitable for money. Small errors accumulate across invoice lines, discounts, and taxes, and rounded totals can be off by a paisa or cent — which is unacceptable in accounting.

Option 1: Integers in the Smallest Unit

Store and calculate amounts in paise (or cents) as integers, and convert only for display.

<?php
$unitPricePaise = 99900;   // ₹999.00
$quantity = 3;
$taxRatePercent = 18;

$subtotal = $unitPricePaise * $quantity;
$tax = intdiv($subtotal * $taxRatePercent + 50, 100);  // round half up to the nearest paisa
$total = $subtotal + $tax;

printf("Subtotal: ₹%s\n", number_format($subtotal / 100, 2));
printf("GST 18%%: ₹%s\n", number_format($tax / 100, 2));
printf("Total:    ₹%s\n", number_format($total / 100, 2));

Output

Subtotal: ₹2,997.00
GST 18%: ₹539.46
Total:    ₹3,536.46

How It Works

  • All arithmetic happens on integers, which are exact.
  • intdiv($subtotal * 18 + 50, 100) calculates 18% and rounds half up: adding 50 (half of 100) before integer division turns truncation into rounding.
  • Division by 100 happens only inside number_format() for display.

Databases support this approach well: store amounts in an integer column (BIGINT) of paise, or use the DECIMAL(12,2) type, which stores exact decimal values.

Option 2: BCMath

The BCMath extension performs arithmetic on decimal strings with exact precision.

<?php
echo bcadd('0.1', '0.2', 1) . "\n";
echo bcmul('999.00', '3', 2) . "\n";
echo bcdiv('10', '3', 4) . "\n";
echo bcadd('0.1', '0.2') . "\n";

Output

0.3
2997.00
3.3333
0
  • The third argument is the scale: the number of decimal places in the result.
  • Without a scale, the default is 0 decimal places, so bcadd('0.1', '0.2') returns "0". Always pass a scale (or set one with bcscale()).
  • BCMath truncates to the scale rather than rounding; calculate with extra decimals and round deliberately when needed.

PHP 8.4: BcMath\Number

PHP 8.4 added an object-oriented API, BcMath\Number, that supports normal arithmetic operators:

<?php
$a = new BcMath\Number('0.1');
$b = new BcMath\Number('0.2');

echo $a + $b;

Output

0.3

The objects are immutable, and the result's scale is chosen automatically for addition, subtraction, and multiplication. Many applications also use dedicated money libraries (such as brick/money or moneyphp/money) installed with Composer, which handle currencies and rounding rules.


When Floats Are the Right Choice

Floats are perfectly appropriate when small relative errors do not matter:

  • Measurements: distances, weights, temperatures
  • Percentages and ratios for display (conversion rates, progress bars)
  • Statistics and averages
  • Coordinates (latitude/longitude)
  • Scientific and graphical calculations

In these cases, round only for display, and compare with a tolerance.


Practical Example: Average Rating

<?php
function averageRating(array $ratings): ?float
{
    if ($ratings === []) {
        return null;
    }

    return array_sum($ratings) / count($ratings);
}

$ratings = [5, 4, 4, 3, 5, 4];

$average = averageRating($ratings);

var_dump($average);
echo "Rating: " . number_format($average, 1) . " / 5\n";
echo "Stars: " . str_repeat("★", (int) round($average)) . "\n";
var_dump(averageRating([]));

Output

float(4.166666666666667)
Rating: 4.2 / 5
Stars: ★★★★
NULL

Step-by-Step Explanation

  1. An empty array returns null — checking first avoids a DivisionByZeroError from count() being 0.
  2. array_sum() returns 25 and count() returns 6; 25 / 6 is a float with many decimal places.
  3. The full-precision value is kept for any further calculations.
  4. number_format($average, 1) rounds for display only: 4.2.
  5. (int) round($average) converts the rating to a whole number of stars. round() returns a float, so the cast produces the integer str_repeat() expects.

Common Mistakes

Comparing Floats With ==

Effect: 0.1 + 0.2 == 0.3 is false.

Fix: Compare with a tolerance or after rounding.

Trusting echo Output While Debugging

Effect: echo shows 0.3 while the value is 0.30000000000000004.

Fix: Use var_dump().

Using Floats for Money

Effect: Totals off by a paisa/cent; accumulated rounding errors.

Fix: Use integers in the smallest unit, DECIMAL columns, BCMath, or a money library.

Converting Formatted Strings Directly

Effect: (float) "1,234.50" is 1.0.

Fix: Remove separators or use filter_var() with FILTER_FLAG_ALLOW_THOUSAND or NumberFormatter::parse().

Forgetting That round(), floor(), and ceil() Return Floats

Effect: Type errors with int parameters in strict mode, or deprecation notices when used as array keys.

Fix: Cast with (int) after rounding.

Comparing NAN With ==

Effect: The comparison is always false.

Fix: Use is_nan().

Omitting the BCMath Scale

Effect: bcadd('0.1', '0.2') returns "0".

Fix: Pass a scale argument or call bcscale().


Best Practices

  • Use floats for measurements and approximate values, not for money.
  • Inspect floats with var_dump(); format them for display with number_format() or sprintf().
  • Compare floats with a tolerance, or round to a known precision before comparing.
  • Convert floats to integers explicitly, choosing truncation or rounding deliberately.
  • Validate decimal input with filter_var(..., FILTER_VALIDATE_FLOAT).
  • Check for INF and NAN with is_finite(), is_infinite(), and is_nan() when inputs can produce them.

Official reference: https://www.php.net/manual/en/language.types.float.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting
Ask about this post
AI Ask about this post

Ask questions about PHP Floats and get answers drawn from it.

Signed-in readers only.