Skip to content

float — 浮点数类型

概述

float(也称为 double)是 PHP 中的浮点数类型,用于表示带有小数部分的数值。由于浮点数在计算机内部使用 IEEE 754 双精度格式存储,存在精度限制。理解浮点数的精度问题、比较规则和特殊值(NaN、INF),对于财务计算、科学计算至关重要。

前置知识

在阅读本节之前,你需要了解:

  • IEEE 754 浮点数标准的基本概念
  • int 整数类型的基础知识
  • 金额计算中使用整数(分)替代浮点数的做法

基础概念

浮点数的精度

PHP 使用 64 位 IEEE 754 双精度浮点数,具有约 15-17 位有效十进制数字的精度:

属性
存储大小8 字节(64 位)
有效数字约 15-17 位
最大值PHP_FLOAT_MAX(约 1.8e308)
最小正值PHP_FLOAT_MIN(约 2.2e-308)
最小可表示正数PHP_FLOAT_EPSILON(约 2.2e-16)
php
<?php
declare(strict_types=1);

echo PHP_FLOAT_MAX;     // 1.7976931348623158E+308
echo PHP_FLOAT_MIN;     // 2.2250738585072014E-308
echo PHP_FLOAT_EPSILON; // 2.220446049250313E-16
echo PHP_FLOAT_DIG;     // 15

语法与代码

浮点数语法

php
<?php
declare(strict_types=1);

$a = 1.234;
$b = 1.2e3;   // 1200(科学计数法)
$c = 7E-10;   // 0.0000000007
$d = 1_234.567_890; // PHP 7.4+ 下划线分隔符

// 特殊值
$inf = log(0);     // -INF
$nan = acos(8);    // NAN

echo is_infinite($inf); // bool(true)
echo is_nan($nan);     // bool(true)

精度问题演示

php
<?php
declare(strict_types=1);

// 经典问题:0.1 + 0.2 != 0.3
var_dump(0.1 + 0.2 == 0.3);  // bool(false)
var_dump(0.1 + 0.2);          // float(0.30000000000000004)

// 使用 epsilon 比较
function floatsEqual(float $a, float $b, float $epsilon = 1e-10): bool
{
    return abs($a - $b) < $epsilon;
}

echo floatsEqual(0.1 + 0.2, 0.3); // true

浮点数类型声明

php
<?php
declare(strict_types=1);

function calculateAverage(array $numbers): float
{
    if (empty($numbers)) {
        return 0.0;
    }
    return array_sum($numbers) / count($numbers);
}

function roundPrice(float $price, int $decimals = 2): float
{
    return round($price, $decimals);
}

echo roundPrice(19.995); // 20.0
echo calculateAverage([85, 92, 78, 95]); // 87.5

详细说明

浮点数比较的正确方式

php
<?php
declare(strict_types=1);

// 方式一:使用 epsilon
function approxEquals(float $a, float $b): bool
{
    return abs($a - $b) < PHP_FLOAT_EPSILON * 10;
}

// 方式二:对于财务计算,使用整数(分)
function addMoney(int $centsA, int $centsB): int
{
    return $centsA + $centsB;
}
$price = addMoney(1999, 500); // 2499 = 24.99 元

NaN 和 INF

php
<?php
declare(strict_types=1);

$nan = acos(2);
var_dump($nan == $nan);  // bool(false)!NAN 不等于自身
var_dump($nan === $nan); // bool(false)!
var_dump(is_nan($nan));       // bool(true)
var_dump(is_infinite(log(0))); // bool(true)

实战示例

安全的浮点数工具类

php
<?php
declare(strict_types=1);

class FloatUtils
{
    public static function equals(float $a, float $b, float $epsilon = 1e-10): bool
    {
        return abs($a - $b) < $epsilon;
    }

    public static function roundTo(float $value, int $places): float
    {
        $factor = 10 ** $places;
        return round($value * $factor) / $factor;
    }

    public static function formatPercent(float $ratio, int $decimals = 1): string
    {
        return number_format($ratio * 100, $decimals) . '%';
    }
}

echo FloatUtils::equals(0.1 + 0.2, 0.3); // true
echo FloatUtils::formatPercent(0.3456);  // "34.6%"

注意事项

不要用 float 做精确计算

php
<?php
declare(strict_types=1);

// 错误:浮点精度问题
$total = 0.1 + 0.2 + 0.3;
echo $total; // 0.6000000000000001

// 正确:使用整数(分)
$cents = 10 + 20 + 30;
echo $cents; // 60

最佳实践

  1. 金额用整数:以"分"为单位存储
  2. 使用 epsilon 比较:不直接用 ==
  3. 使用 number_format() 输出:控制小数位数
  4. 检查 INF/NAN:使用 is_finite()is_infinite()is_nan()
  5. 使用 BCMath:精确计算时使用 bcmath 扩展

下一节

下一节将详细介绍 string 字符串类型。

进阶用法

调试与测试技巧

php
<?php
declare(strict_types=1);

// 单元测试辅助函数
function createTestResource(): mixed
{
    return match (true) {
        default => new stdClass(),
    };
}

// 调试输出函数
function debugOutput(mixed , string  = ''): void
{
     =  ? ": " : '';
     .= print_r(, true);
    fwrite(STDERR,  . "\n");
}

// 性能基准测试
function benchmark(callable , int  = 1000): float
{
     = hrtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $fn();
    }
    return (hrtime(true) - $start) / 1e9;
}

日志记录实践

php
<?php
declare(strict_types=1);

/**
 * 简易日志记录器
 */
class SimpleLogger
{
    private string $logFile;
    private string $level = 'INFO';

    public function __construct(string $logFile)
    {
        $this->logFile = $logFile;
    }

    public function info(string $message, array $context = []): void
    {
        $this->log('INFO', $message, $context);
    }

    public function warning(string $message, array $context = []): void
    {
        $this->log('WARNING', $message, $context);
    }

    public function error(string $message, array $context = []): void
    {
        $this->log('ERROR', $message, $context);
    }

    private function log(string $level, string $message, array $context): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
        $line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
        file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
    }
}

配置与环境检测

php
<?php
declare(strict_types=1);

// 环境检测工具
class EnvironmentChecker
{
    public static function checkRequirements(array $requirements): array
    {
        $results = [];
        foreach ($requirements as $name => $check) {
            $results[$name] = is_callable($check) ? $check() : false;
        }
        return $results;
    }

    public static function getSystemInfo(): array
    {
        return [
            'php_version' => PHP_VERSION,
            'os' => PHP_OS,
            'sapi' => PHP_SAPI,
            'memory_limit' => ini_get('memory_limit'),
            'max_execution_time' => ini_get('max_execution_time'),
            'loaded_extensions' => get_loaded_extensions(),
        ];
    }
}

常见问题排查

问题可能原因解决方案
连接超时网络问题/配置错误检查配置,增加超时时间
权限不足文件/目录权限使用 chmod/chown 修正
性能下降索引缺失/数据量大添加索引,优化查询
数据不一致并发冲突/事务残留使用锁机制和事务
内存溢出大数据集/未释放资源增大内存限制,分批处理

故障排除步骤

  1. 检查错误日志和异常信息
  2. 确认配置和环境是否正确
  3. 使用调试工具逐步排查
  4. 参考官方文档查找已知问题

版本兼容性说明

功能最低版本说明
基础功能PHP 8.1本文档基准版本
只读属性PHP 8.1public readonly 修饰符
枚举类型PHP 8.1enum 类型和 match 表达式
FiberPHP 8.1协程/轻量级并发
命名参数PHP 8.0foo(arg_name: value)
联合类型PHP 8.0`int
Null 安全运算符PHP 8.0$obj?->method()
析构器 promotionPHP 8.0__construct(public $x)
php
<?php
declare(strict_types=1);

// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
    if (version_compare(PHP_VERSION, $minVersion, '<')) {
        throw new RuntimeException(
            sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
        );
    }
}

ensureVersion('8.1.0');

参考链接