FFmpeg
Loading...
Searching...
No Matches
rational64.c
Go to the documentation of this file.
1/*
2 * 64-bit rational numbers
3 * Copyright (c) 2025 Niklas Haas
4 * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23/**
24 * @file
25 * 64-bit rational numbers
26 * @author Niklas Haas
27 */
28
29#include <limits.h>
30
32#include "libavutil/common.h"
33#include "libavutil/int128.h"
34#include "libavutil/intmath.h"
35#include "rational64.h"
36
37static av_always_inline uint64_t high64(av_int128 a)
38{
39 return av_from128u(av_shr128(a, 64));
40}
41
42/* unsigned version of av_gcd(); see libavutil/mathematics.c */
43static av_always_inline uint64_t gcd_u64(uint64_t a, uint64_t b)
44{
45 if (!a)
46 return b;
47 if (!b)
48 return a;
49
50 const int k = ff_ctzll(a | b);
51 a >>= ff_ctzll(a);
52 do {
53 b >>= ff_ctzll(b);
54 if (a > b)
55 FFSWAP(uint64_t, a, b);
56 b -= a;
57 } while (b);
58 return a << k;
59}
60
61static av_int128 gcd128(av_int128 a, av_int128 b)
62{
63 while (av_test128(b)) {
64 av_int128 tmp = b;
65 b = av_mod128(a, b);
66 a = tmp;
67 }
68 return a;
69}
70
71static AVRational64 reduce64(av_int128 num, av_int128 den)
72{
73 const av_int128 zero = av_to128i(0);
74 const av_int128 max = av_to128i(INT64_MAX);
75 const int num_sign = av_cmp128(num, zero) < 0;
76 const int den_sign = av_cmp128(den, zero) < 0;
77 if (num_sign)
79 if (den_sign)
80 den = av_sub128(zero, den);
81
82 if (!high64(num) && !high64(den)) {
83 /* Fast path: both values already fit into 64 bits */
84 uint64_t n = av_from128u(num), d = av_from128u(den);
85 const uint64_t gcd = gcd_u64(n, d);
86 if (gcd) {
87 n /= gcd;
88 d /= gcd;
89 }
90
91 if (!((n | d) >> 63)) {
92 AVRational64 res = { n, d };
93 if (num_sign ^ den_sign)
94 res.num = -res.num;
95 return res;
96 }
97
98 /* Fall back to 128-bit arithmetic for values > INT64_MAX */
99 num = av_to128u(n);
100 den = av_to128u(d);
101 }
102
103 const av_int128 gcd = gcd128(num, den);
104 if (av_test128(gcd)) {
105 num = av_div128(num, gcd);
106 den = av_div128(den, gcd);
107 }
108
109 av_uint128 a0n = av_to128u(0), a0d = av_to128u(1);
110 av_uint128 a1n = av_to128u(1), a1d = av_to128u(0);
111 if (av_cmp128(num, max) <= 0 && av_cmp128(den, max) <= 0) {
112 a1n = num;
113 a1d = den;
114 goto done;
115 }
116
117 while (av_test128(den)) {
118 av_int128 x = av_div128(num, den);
119 av_int128 next_den = av_sub128(num, av_mul128(den, x));
120 av_uint128 a2n = av_add128(av_mul128(x, a1n), a0n);
121 av_uint128 a2d = av_add128(av_mul128(x, a1d), a0d);
122
123 if (av_cmp128(a2n, max) > 0 || av_cmp128(a2d, max) > 0) {
124 if (av_test128(a1n))
125 x = av_div128(av_sub128(max, a0n), a1n);
126 if (av_test128(a1d)) {
127 av_uint128 tmp = av_div128(av_sub128(max, a0d), a1d);
128 x = av_min128(x, tmp);
129 }
130
131 av_uint128 x1d = av_mul128(x, a1d);
132 av_uint128 a = av_mul128(den, av_add128(av_add128(x1d, x1d), a0d));
133 av_uint128 b = av_mul128(num, a1d);
134 if (av_cmp128(a, b) > 0) {
135 a1n = av_add128(av_mul128(x, a1n), a0n);
136 a1d = av_add128(x1d, a0d);
137 }
138 break;
139 }
140
141 a0n = a1n;
142 a0d = a1d;
143 a1n = a2n;
144 a1d = a2d;
145 num = den;
146 den = next_den;
147 }
148
149done:;
150 AVRational64 res = { av_from128i(a1n), av_from128i(a1d) };
151 if (num_sign ^ den_sign)
152 res.num = -res.num;
153 return res;
154}
155
157{
158 return x >= -INT32_MAX && x <= INT32_MAX;
159}
160
162{
163 return fits31(b.num) && fits31(b.den) && fits31(c.num) && fits31(c.den);
164}
165
166/* Simplified version of reduce64() for small values */
168{
169 const int sign = (num < 0) ^ (den < 0);
170 uint64_t n = num < 0 ? -(uint64_t) num : num;
171 uint64_t d = den < 0 ? -(uint64_t) den : den;
172 const uint64_t gcd = gcd_u64(n, d);
173 if (gcd) {
174 n /= gcd;
175 d /= gcd;
176 }
177
178 AVRational64 res = { n, d };
179 if (sign)
180 res.num = -res.num;
181 return res;
182}
183
184
186{
187 int test;
188 if (fits31_q(a, b)) {
189 const int64_t p = a.num * b.den;
190 const int64_t q = b.num * a.den;
191 test = (p > q) - (p < q);
192 } else {
193 const av_int128 p = av_mul128(av_to128i(a.num), av_to128i(b.den));
194 const av_int128 q = av_mul128(av_to128i(b.num), av_to128i(a.den));
195 test = av_cmp128(p, q);
196 }
197
198 if (test)
199 return (a.den < 0) ^ (b.den < 0) ? -test : test;
200 else if (b.den && a.den)
201 return 0;
202 else if (a.num && b.num)
203 return (a.num >> 63) - (b.num >> 63);
204 else
205 return INT_MIN;
206}
207
209{
210 if (fits31_q(b, c))
211 return reduce64_fast(b.num * c.num, b.den * c.den);
212
213 return reduce64(av_mul128(av_to128i(b.num), av_to128i(c.num)),
214 av_mul128(av_to128i(b.den), av_to128i(c.den)));
215}
216
221
223{
224 if (fits31_q(b, c))
225 return reduce64_fast(b.num * c.den + c.num * b.den, b.den * c.den);
226
227 return reduce64(av_add128(av_mul128(av_to128i(b.num), av_to128i(c.den)),
228 av_mul128(av_to128i(c.num), av_to128i(b.den))),
229 av_mul128(av_to128i(b.den), av_to128i(c.den)));
230}
231
233{
234 if (fits31_q(b, c))
235 return reduce64_fast(b.num * c.den - c.num * b.den, b.den * c.den);
236
237 return reduce64(av_sub128(av_mul128(av_to128i(b.num), av_to128i(c.den)),
238 av_mul128(av_to128i(c.num), av_to128i(b.den))),
239 av_mul128(av_to128i(b.den), av_to128i(c.den)));
240}
common internal and external API header
long long int64_t
Definition coverity.c:34
#define max(a, b)
static av_always_inline AVRational64 ff_inv_q64(AVRational64 q)
Invert a 64-bit rational.
Definition rational64.h:131
AVRational64 ff_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition rational64.c:208
AVRational64 ff_sub_q64(AVRational64 b, AVRational64 c)
Subtract one 64-bit rational from another.
Definition rational64.c:232
AVRational64 ff_div_q64(AVRational64 b, AVRational64 c)
Divide one 64-bit rational by another.
Definition rational64.c:217
AVRational64 ff_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition rational64.c:222
int ff_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition rational64.c:185
#define ff_ctzll
Definition intmath.h:125
int a
#define b
Definition input.c:43
128-bit integers, falling back to integer.h if necessary
#define av_mul128(a, b)
Definition int128.h:73
#define av_test128(a)
Definition int128.h:84
#define av_min128(a, b)
Definition int128.h:76
#define av_from128u(a)
Definition int128.h:83
#define av_shr128(a, b)
Definition int128.h:80
#define av_cmp128(a, b)
Definition int128.h:75
#define av_sub128(a, b)
Definition int128.h:72
static av_always_inline av_uint128 av_to128u(uint64_t a)
Definition int128.h:86
#define av_from128i(a)
Definition int128.h:82
#define av_add128(a, b)
Definition int128.h:71
#define av_mod128(a, b)
Definition int128.h:79
#define av_to128i(a)
Definition int128.h:81
#define av_div128(a, b)
Definition int128.h:74
static int zero(InterplayACMContext *s, unsigned ind, unsigned col)
Macro definitions for various function/variable attributes.
#define av_always_inline
Definition attributes.h:72
#define FFSWAP(type, a, b)
Definition macros.h:52
static av_always_inline int fits31_q(AVRational64 b, AVRational64 c)
Definition rational64.c:161
static av_always_inline int fits31(int64_t x)
Definition rational64.c:156
static AVRational64 reduce64_fast(int64_t num, int64_t den)
Definition rational64.c:167
static av_always_inline uint64_t high64(av_int128 a)
Definition rational64.c:37
static AVRational64 reduce64(av_int128 num, av_int128 den)
Definition rational64.c:71
static av_int128 gcd128(av_int128 a, av_int128 b)
Definition rational64.c:61
static av_always_inline uint64_t gcd_u64(uint64_t a, uint64_t b)
Definition rational64.c:43
64-bit extension of AVRational.
64-bit Rational number (pair of numerator and denominator).
Definition rational64.h:52
int64_t num
Numerator.
Definition rational64.h:53
Definition idctdsp.c:35
static uint8_t tmp[40]
Definition aes_ctr.c:52
int num
Definition error.c:23
static double c[64]