vinyl-cache/vmod/vmod_math_util.c
0
/*-
1
 * Copyright 2025 UPLEX - Nils Goroll Systemoptimierung
2
 * All rights reserved.
3
 *
4
 * Author: Nils Goroll <slink@uplex.de>
5
 *
6
 * Includes code by Bruce Dawson
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include "config.h"
33
34
#include <float.h>
35
#include <math.h>
36
37
#include "cache/cache.h"
38
#include "vcc_math_if.h"
39
40
// macros in math.h code are generic-ish across float/double/long double
41
//lint --e{506} Constant value Boolean
42
//lint --e{736} Loss of precision
43
44
/*
45
 * this is AlmostEqualRelativeAndAbs() by Bruce Dawson
46
 * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
47
 */
48
VCL_BOOL
49 8
vmod_approx(VRT_CTX, VCL_REAL a, VCL_REAL b, VCL_REAL maxDiff, VCL_REAL maxRelDiff)
50
{
51 8
        (void)ctx;
52
53 8
        if (fpclassify(maxDiff) == FP_ZERO)
54 8
                maxDiff = 4 * DBL_EPSILON;
55
56 8
        if (fpclassify(maxRelDiff) == FP_ZERO)
57 8
                maxRelDiff = DBL_EPSILON;
58
59 8
        VCL_REAL diff = fabs(a - b);
60 8
        if (diff <= maxDiff)
61 4
                return (1);
62
63 4
        a = fabs(a);
64 4
        b = fabs(b);
65 4
        VCL_REAL largest = (b > a) ? b : a;
66
67 4
        if (diff <= largest * maxRelDiff)
68 4
                return (1);
69
70 0
        return (0);
71 8
}
72
73
static int
74 36
valid_fmt(VCL_STRING fmt)
75
{
76 36
        if (fmt == NULL || *fmt != '%')
77 0
                return (0);
78 36
        fmt++;
79 36
        if (*fmt == '.') {
80 16
                fmt++;
81 48
                while (*fmt >= '0' && *fmt <= '9')
82 32
                        fmt++;
83 16
        }
84
85 36
        if (fmt[0] == '\0' || fmt[1] != '\0')
86 8
                return (0);
87
88 28
        switch (*fmt) {
89
        case 'a':
90
        case 'A':
91
        case 'e':
92
        case 'E':
93
        case 'f':
94
        case 'F':
95
        case 'g':
96
        case 'G':
97 28
                return (1);
98
        default:
99 0
                return (0);
100
        }
101 36
}
102
103
VCL_STRING
104 36
vmod_strfromd(VRT_CTX, VCL_STRING fmt, VCL_REAL fp)
105
{
106 36
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
107
108 36
        if (! valid_fmt(fmt)) {
109 16
                VRT_fail(ctx, "math.strfromd(\"%s\", ...): Invalid format",
110 8
                    fmt ? fmt : "<NULL>");
111 8
                return (NULL);
112
        }
113
114 28
        return (WS_Printf(ctx->ws, fmt, fp));
115 36
}