FFmpeg
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 
31 #include "libavutil/int128.h"
32 #include "rational64.h"
33 
35 {
36  while (av_test128(b)) {
37  av_int128 tmp = b;
38  b = av_mod128(a, b);
39  a = tmp;
40  }
41  return a;
42 }
43 
45 {
46  const av_int128 zero = av_to128i(0);
47  const av_int128 max = av_to128i(INT64_MAX);
48  const int num_sign = av_cmp128(num, zero) < 0;
49  const int den_sign = av_cmp128(den, zero) < 0;
50  if (num_sign)
51  num = av_sub128(zero, num);
52  if (den_sign)
53  den = av_sub128(zero, den);
54 
55  const av_int128 gcd = gcd128(num, den);
56  if (av_test128(gcd)) {
57  num = av_div128(num, gcd);
58  den = av_div128(den, gcd);
59  }
60 
61  av_uint128 a0n = av_to128u(0), a0d = av_to128u(1);
62  av_uint128 a1n = av_to128u(1), a1d = av_to128u(0);
63  if (av_cmp128(num, max) <= 0 && av_cmp128(den, max) <= 0) {
64  a1n = num;
65  a1d = den;
66  goto done;
67  }
68 
69  while (av_test128(den)) {
70  av_int128 x = av_div128(num, den);
71  av_int128 next_den = av_sub128(num, av_mul128(den, x));
72  av_uint128 a2n = av_add128(av_mul128(x, a1n), a0n);
73  av_uint128 a2d = av_add128(av_mul128(x, a1d), a0d);
74 
75  if (av_cmp128(a2n, max) > 0 || av_cmp128(a2d, max) > 0) {
76  if (av_test128(a1n))
77  x = av_div128(av_sub128(max, a0n), a1n);
78  if (av_test128(a1d)) {
79  av_uint128 tmp = av_div128(av_sub128(max, a0d), a1d);
80  x = av_min128(x, tmp);
81  }
82 
83  av_uint128 x1d = av_mul128(x, a1d);
84  av_uint128 a = av_mul128(den, av_add128(av_add128(x1d, x1d), a0d));
85  av_uint128 b = av_mul128(num, a1d);
86  if (av_cmp128(a, b) > 0) {
87  a1n = av_add128(av_mul128(x, a1n), a0n);
88  a1d = av_add128(x1d, a0d);
89  }
90  break;
91  }
92 
93  a0n = a1n;
94  a0d = a1d;
95  a1n = a2n;
96  a1d = a2d;
97  num = den;
98  den = next_den;
99  }
100 
101 done:;
102  AVRational64 res = { av_from128i(a1n), av_from128i(a1d) };
103  if (num_sign ^ den_sign)
104  res.num = -res.num;
105  return res;
106 }
107 
109 {
110  const av_int128 p = av_mul128(av_to128i(a.num), av_to128i(b.den));
111  const av_int128 q = av_mul128(av_to128i(b.num), av_to128i(a.den));
112  const int test = av_cmp128(p, q);
113 
114  if (test)
115  return (a.den < 0) ^ (b.den < 0) ? -test : test;
116  else if (b.den && a.den)
117  return 0;
118  else if (a.num && b.num)
119  return (a.num >> 63) - (b.num >> 63);
120  else
121  return INT_MIN;
122 }
123 
125 {
126  return reduce64(av_mul128(av_to128i(b.num), av_to128i(c.num)),
127  av_mul128(av_to128i(b.den), av_to128i(c.den)));
128 }
129 
131 {
132  return av_mul_q64(b, av_inv_q64(c));
133 }
134 
136  return reduce64(av_add128(av_mul128(av_to128i(b.num), av_to128i(c.den)),
137  av_mul128(av_to128i(c.num), av_to128i(b.den))),
138  av_mul128(av_to128i(b.den), av_to128i(c.den)));
139 }
140 
142 {
143  return reduce64(av_sub128(av_mul128(av_to128i(b.num), av_to128i(c.den)),
144  av_mul128(av_to128i(c.num), av_to128i(b.den))),
145  av_mul128(av_to128i(b.den), av_to128i(c.den)));
146 }
av_to128u
static av_always_inline av_uint128 av_to128u(uint64_t a)
Definition: int128.h:86
av_mul128
#define av_mul128(a, b)
Definition: int128.h:73
b
#define b
Definition: input.c:43
test
Definition: idctdsp.c:35
av_mod128
#define av_mod128(a, b)
Definition: int128.h:79
av_test128
#define av_test128(a)
Definition: int128.h:84
max
#define max(a, b)
Definition: cuda_runtime.h:33
av_min128
#define av_min128(a, b)
Definition: int128.h:76
av_cmp_q64
int av_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition: rational64.c:108
limits.h
av_mul_q64
AVRational64 av_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition: rational64.c:124
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
av_add128
#define av_add128(a, b)
Definition: int128.h:71
int128.h
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
av_div_q64
AVRational64 av_div_q64(AVRational64 b, AVRational64 c)
Divide one 64-bit rational by another.
Definition: rational64.c:130
av_sub_q64
AVRational64 av_sub_q64(AVRational64 b, AVRational64 c)
Subtract one 64-bit rational from another.
Definition: rational64.c:141
av_cmp128
#define av_cmp128(a, b)
Definition: int128.h:75
AVRational64
64-bit Rational number (pair of numerator and denominator).
Definition: rational64.h:52
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
zero
static int zero(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:121
av_from128i
#define av_from128i(a)
Definition: int128.h:82
AVInteger
Definition: integer.h:36
av_sub128
#define av_sub128(a, b)
Definition: int128.h:72
reduce64
static AVRational64 reduce64(av_int128 num, av_int128 den)
Definition: rational64.c:44
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
rational64.h
AVRational64::num
int64_t num
Numerator.
Definition: rational64.h:53
av_to128i
#define av_to128i(a)
Definition: int128.h:81
gcd128
static av_int128 gcd128(av_int128 a, av_int128 b)
Definition: rational64.c:34
av_div128
#define av_div128(a, b)
Definition: int128.h:74
av_inv_q64
static av_always_inline AVRational64 av_inv_q64(AVRational64 q)
Invert a 64-bit rational.
Definition: rational64.h:131
av_add_q64
AVRational64 av_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition: rational64.c:135