Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/base/SkFloatingPoint.cpp
Line
Count
Source
1
/*
2
 * Copyright 2023 Google LLC
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "include/private/base/SkFloatingPoint.h"
9
10
#include <algorithm>
11
#include <cmath>
12
#include <cstring>
13
#include <limits>
14
15
// Return the positive magnitude of a double.
16
// * normalized - given 1.bbb...bbb x 2^e return 2^e.
17
// * subnormal - return 0.
18
// * nan & infinity - return infinity
19
9.76M
static double magnitude(double a) {
20
9.76M
    static constexpr int64_t extractMagnitude =
21
9.76M
            0b0'11111111111'0000000000000000000000000000000000000000000000000000;
22
9.76M
    int64_t bits;
23
9.76M
    memcpy(&bits, &a, sizeof(bits));
24
9.76M
    bits &= extractMagnitude;
25
9.76M
    double out;
26
9.76M
    memcpy(&out, &bits, sizeof(out));
27
9.76M
    return out;
28
9.76M
}
29
30
4.88M
bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff) {
31
32
    // The maximum magnitude to construct the ulp tolerance. The proper magnitude for
33
    // subnormal numbers is minMagnitude, which is 2^-1021, so if a and b are subnormal (having a
34
    // magnitude of 0) use minMagnitude. If a or b are infinity or nan, then maxMagnitude will be
35
    // +infinity. This means the tolerance will also be infinity, but the expression b - a below
36
    // will either be NaN or infinity, so a tolerance of infinity doesn't matter.
37
4.88M
    static constexpr double minMagnitude = std::numeric_limits<double>::min();
38
4.88M
    const double maxMagnitude = std::max(std::max(magnitude(a), minMagnitude), magnitude(b));
39
40
    // Given a magnitude, this is the factor that generates the ulp for that magnitude.
41
    // In numbers, 2 ^ (-precision + 1) = 2 ^ -52.
42
4.88M
    static constexpr double ulpFactor = std::numeric_limits<double>::epsilon();
43
44
    // The tolerance in ULPs given the maxMagnitude. Because the return statement must use <
45
    // for comparison instead of <= to correctly handle infinities, bump maxUlpsDiff up to get
46
    // the full maxUlpsDiff range.
47
4.88M
    const double tolerance = maxMagnitude * (ulpFactor * (maxUlpsDiff + 1));
48
49
    // The expression a == b is mainly for handling infinities, but it also catches the exact
50
    // equals.
51
4.88M
    return a == b || std::abs(b - a) < tolerance;
52
4.88M
}
53
54
14.6M
bool sk_double_nearly_zero(double a) {
55
14.6M
    return a == 0 || fabs(a) < std::numeric_limits<float>::epsilon();
56
14.6M
}