xref: /aosp_15_r20/external/skia/fuzz/FuzzCubicRoots.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "fuzz/Fuzz.h"
9 #include "include/private/base/SkAssert.h"
10 #include "include/private/base/SkFloatingPoint.h"
11 #include "src/base/SkCubics.h"
12 #include "src/base/SkQuads.h"
13 #include "src/base/SkUtils.h"
14 
15 #include <cmath>
16 
fuzz_cubic_real_roots(double A,double B,double C,double D)17 static void fuzz_cubic_real_roots(double A, double B, double C, double D) {
18     double roots[3];
19     const int numSolutions = SkCubics::RootsReal(A, B, C, D, roots);
20     SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
21     for (int i = 0; i < numSolutions; i++) {
22         SkASSERT_RELEASE(std::isfinite(roots[i]));
23     }
24     // Roots should not be duplicated
25     if (numSolutions >= 2) {
26         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
27     }
28     if (numSolutions == 3) {
29         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
30         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
31     }
32 }
33 
fuzz_cubic_roots_valid_t(double A,double B,double C,double D)34 static void fuzz_cubic_roots_valid_t(double A, double B, double C, double D) {
35     double roots[3];
36     const int numSolutions = SkCubics::RootsValidT(A, B, C, D, roots);
37     SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
38     for (int i = 0; i < numSolutions; i++) {
39         SkASSERT_RELEASE(std::isfinite(roots[i]));
40         SkASSERT_RELEASE(roots[i] >= 0.0);
41         SkASSERT_RELEASE(roots[i] <= 1.0);
42     }
43     // Roots should not be duplicated
44     if (numSolutions >= 2) {
45         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
46     }
47     if (numSolutions == 3) {
48         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
49         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
50     }
51 }
52 
fuzz_cubic_roots_binary_search(double A,double B,double C,double D)53 static void fuzz_cubic_roots_binary_search(double A, double B, double C, double D) {
54     double roots[3];
55     const int numSolutions = SkCubics::BinarySearchRootsValidT(A, B, C, D, roots);
56     SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
57     for (int i = 0; i < numSolutions; i++) {
58         SkASSERT_RELEASE(std::isfinite(roots[i]));
59         SkASSERT_RELEASE(roots[i] >= 0.0);
60         SkASSERT_RELEASE(roots[i] <= 1.0);
61         double actual = SkCubics::EvalAt(A, B, C, D, roots[i]);
62         // The binary search algorithm *should* be accurate regardless of the inputs.
63         SkASSERT_RELEASE(std::abs(actual) < 0.001);
64     }
65     // Roots should not be duplicated
66     if (numSolutions >= 2) {
67         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
68     }
69     if (numSolutions == 3) {
70         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
71         SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
72     }
73 }
74 
DEF_FUZZ(CubicRoots,fuzz)75 DEF_FUZZ(CubicRoots, fuzz) {
76     double A, B, C, D;
77     fuzz->next(&A);
78     fuzz->next(&B);
79     fuzz->next(&C);
80     fuzz->next(&D);
81 
82     // Uncomment for easy test case creation
83 //    SkDebugf("A %16e (0x%lx) B %16e (0x%lx) C %16e (0x%lx) D %16e (0x%lx)\n",
84 //             A, sk_bit_cast<uint64_t>(A), B, sk_bit_cast<uint64_t>(B),
85 //             C, sk_bit_cast<uint64_t>(C), D, sk_bit_cast<uint64_t>(D));
86     fuzz_cubic_real_roots(A, B, C, D);
87 
88     fuzz_cubic_roots_valid_t(A, B, C, D);
89 
90     fuzz_cubic_roots_binary_search(A, B, C, D);
91 }
92