PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
ta_compare_band.hpp
Go to the documentation of this file.
1#pragma once
2// Absolute-band float comparison used by the TA builtins.
3//
4// Two finite doubles at most 1e-10 apart compare EQUAL (inclusive at exactly
5// 1e-10), independent of magnitude, and strict `<` / `>` are suppressed inside
6// the band. The band is a calibration, not an IEEE relaxation: it is the rule
7// TradingView's own relational operators and builtins follow, measured with
8// `lab tv` on NYSE:F 15m (round 7 family K, 2026-09-05, scratchpad/r7/pins/
9// f15-eps-{abs,rel}, 20 qty-encoded decisions): at m = 11.5, a = m + d vs
10// b = m answers a > b for d = 1e-8 / 1e-9 / 1e-10 (the double diff at 11.5
11// sits one ulp ABOVE 1e-10) and EQUAL for d = 1e-11 .. 1e-14; d = 1e-10 at
12// m = 1, 1000, 100000 answers a > b (diffs 1.0000000827e-10, 1.00044e-10,
13// 1.0186e-10 — all above the band, so it is not relative to |a|); a fixed
14// relative diff 1e-11 is EQUAL at m = 0.01 (1e-13) and 1 (1e-11) but a > b
15// at m = 100 (1e-9), 1e4 and 1e6; 1e-10 vs 0 is EQUAL (inclusive edge),
16// 1.1e-10 vs 0 is a > b, 0.9e-10 vs 0 EQUAL; 11.58-11.565 vs 11.54-11.525
17// (diff 1.78e-15) and 0.1+0.2 vs 0.3 are EQUAL. The builtins that decide on
18// two derived doubles (ta.dmi's up > down, ta.percentrank's src[i] <= src)
19// use these helpers so the engine answers the ties those builtins answer —
20// the 2025-07-15 19:30Z NYSE:F bar (up = 11.58-11.565, down = 11.54-11.525,
21// both 0.015 in decimal) gives plusDM 0 AND minusDM 0 on TradingView
22// (`lab tv` f15-plusdm-perbar-0714 / f15-dmi-internals-0718), where a strict
23// IEEE compare hands the 0.015 to one side. A source frontend lowers its own
24// script-level float relationals to the same predicate (KI-73, visit_expr.py
25// _emit_float_relational); the deprecated `pine_float_*` spellings of these
26// helpers live in the source-layer header
27// <pineforge/source/pine_float_compare.hpp>.
28//
29// na (NaN) operands make every relational false, `!=` included; infinities
30// compare by value (equal infinities are equal, a finite/infinite pair is
31// ordered).
32#include <cmath>
33
34namespace pineforge {
35
36inline constexpr double kFloatCompareBand = 1e-10;
37
38inline bool float_band_eq(double a, double b) {
39 if (std::isnan(a) || std::isnan(b)) return false;
40 return a == b
41 || (std::isfinite(a) && std::isfinite(b)
42 && std::fabs(a - b) <= kFloatCompareBand);
43}
44
45inline bool float_band_ne(double a, double b) {
46 if (std::isnan(a) || std::isnan(b)) return false;
47 return !float_band_eq(a, b);
48}
49
50inline bool float_band_gt(double a, double b) {
51 if (std::isnan(a) || std::isnan(b)) return false;
52 return a > b && !float_band_eq(a, b);
53}
54
55inline bool float_band_lt(double a, double b) {
56 if (std::isnan(a) || std::isnan(b)) return false;
57 return a < b && !float_band_eq(a, b);
58}
59
60inline bool float_band_ge(double a, double b) {
61 if (std::isnan(a) || std::isnan(b)) return false;
62 return a > b || float_band_eq(a, b);
63}
64
65inline bool float_band_le(double a, double b) {
66 if (std::isnan(a) || std::isnan(b)) return false;
67 return a < b || float_band_eq(a, b);
68}
69
70} // namespace pineforge
bool float_band_ne(double a, double b)
bool float_band_lt(double a, double b)
bool float_band_le(double a, double b)
bool float_band_eq(double a, double b)
bool float_band_gt(double a, double b)
constexpr double kFloatCompareBand
bool float_band_ge(double a, double b)