You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法复现Chrome中performance.now()的精度误差问题

问题

在Chromium浏览器中调用performance.now()时,会出现如下示例中的输出结果:

147.5
150.09999990463257
151.19999980926514
152.09999990463257
156.59999990463257
164.89999985694885
168.89999985694885
172.89999985694885
176.89999985694885
180.29999995231628
185
188.89999985694885
192.59999990463257
196.39999985694885
201.09999990463257
209
212.5
217.09999990463257
220.79999995231628

已知该误差由浮点精度问题导致,但无法在C或JavaScript中复现此类误差,测试的C代码产生的误差与Chromium中的完全不同:

int main() {
    float sum = 100.0;
    for (int i = 0; i < 1000; i++) {
        sum += 0.1;
        std::cout << std::fixed << std::setprecision(17);

        std::cout << "Actual sum: " << sum << std::endl;
    }
    return 0;
}

请问该现象的具体成因是什么?如何通过代码复现Chromium中performance.now()的精度误差?

成因与复现方法

具体成因

  • 计时逻辑本质差异:Chromium的performance.now()并非通过循环累加固定时间间隔实现,而是读取系统高精度计时器(如Windows的QueryPerformanceCounter、Linux的CLOCK_MONOTONIC)返回的原始整数时间戳(单位多为纳秒或微秒),再将其转换为毫秒级的double浮点数。由于部分整数无法被二进制浮点数精确表示,转换时就会出现示例中的尾数位误差。
  • 浮点数类型与误差来源不同:你测试用的C++代码使用单精度float类型,而Chromium内部采用双精度double类型,两者的精度范围、误差模式完全不同;同时你的代码是累加本身就无法精确表示的0.1浮点数,和直接转换整数时间戳的误差来源完全无关,自然复现不了相同结果。

复现方法

JavaScript复现

模拟Chromium的整数转浮点数逻辑,直接将高精度整数时间戳转换为毫秒级double:

function simulatePerformanceNow() {
    // 模拟获取微秒级原始整数时间戳
    const microseconds = BigInt(Date.now()) * 1000n + BigInt(Math.floor(Math.random() * 1000));
    // 转换为毫秒级double
    return Number(microseconds) / 1000;
}

// 多次调用查看误差结果
for (let i = 0; i < 20; i++) {
    console.log(simulatePerformanceNow());
}

运行后会输出类似Chromium中的浮点误差,因为大整数转换为double时,部分数值无法精确表示,会产生对应的尾数位。

C++复现

改用double类型模拟高精度时间戳的单位转换逻辑,而非累加0.1:

#include <iostream>
#include <chrono>
#include <iomanip>
#include <thread>

int main() {
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 20; i++) {
        auto now = std::chrono::high_resolution_clock::now();
        // 获取纳秒级整数时间差
        long long nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start).count();
        // 转换为毫秒级double
        double ms = static_cast<double>(nanoseconds) / 1000000.0;
        std::cout << std::fixed << std::setprecision(17) << ms << std::endl;
        // 模拟微小延迟,让时间差变化更明显
        std::chrono::microseconds delay(100);
        std::this_thread::sleep_for(delay);
    }
    return 0;
}

这段代码通过系统高精度计时器获取纳秒级整数,再转换为毫秒级double,和Chromium内部performance.now()的核心逻辑一致,会产生和示例中类似的浮点误差。

内容的提问来源于stack exchange,提问作者BayanR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 02:57:46