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最佳实践
- 金额用整数:以"分"为单位存储
- 使用 epsilon 比较:不直接用
== - 使用 number_format() 输出:控制小数位数
- 检查 INF/NAN:使用
is_finite()、is_infinite()、is_nan() - 使用 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 修正 |
| 性能下降 | 索引缺失/数据量大 | 添加索引,优化查询 |
| 数据不一致 | 并发冲突/事务残留 | 使用锁机制和事务 |
| 内存溢出 | 大数据集/未释放资源 | 增大内存限制,分批处理 |
故障排除步骤
- 检查错误日志和异常信息
- 确认配置和环境是否正确
- 使用调试工具逐步排查
- 参考官方文档查找已知问题
版本兼容性说明
| 功能 | 最低版本 | 说明 |
|---|---|---|
| 基础功能 | PHP 8.1 | 本文档基准版本 |
| 只读属性 | PHP 8.1 | public readonly 修饰符 |
| 枚举类型 | PHP 8.1 | enum 类型和 match 表达式 |
| Fiber | PHP 8.1 | 协程/轻量级并发 |
| 命名参数 | PHP 8.0 | foo(arg_name: value) |
| 联合类型 | PHP 8.0 | `int |
| Null 安全运算符 | PHP 8.0 | $obj?->method() |
| 析构器 promotion | PHP 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');