From 38235bc145b13f8d26a0505423b7f7def62e8d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 25 May 2017 17:19:01 +0800 Subject: [PATCH] Add MetaFraction for dealing with fractions Add MetaFraction, which consists of two integers, the numerator an the denominator. The utility function to convert a double to a MetaFraction comes from gstreamer. https://bugzilla.gnome.org/show_bug.cgi?id=784199 --- src/Makefile.am | 2 + src/core/meta-fraction.c | 134 +++++++++++++++++++++++++++++++++++++++ src/core/meta-fraction.h | 31 +++++++++ 3 files changed, 167 insertions(+) create mode 100644 src/core/meta-fraction.c create mode 100644 src/core/meta-fraction.h diff --git a/src/Makefile.am b/src/Makefile.am index 5c0a55383..d88539b04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -174,6 +174,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \ meta/boxes.h \ core/meta-border.c \ core/meta-border.h \ + core/meta-fraction.c \ + core/meta-fraction.h \ compositor/clutter-utils.c \ compositor/clutter-utils.h \ compositor/cogl-utils.c \ diff --git a/src/core/meta-fraction.c b/src/core/meta-fraction.c new file mode 100644 index 000000000..8090aa411 --- /dev/null +++ b/src/core/meta-fraction.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2002 Thomas Vander Stichele + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Fraction utility functions in this file comes from gstutils.c in gstreamer. + */ + +#include "config.h" + +#include "core/meta-fraction.h" + +#include +#include + +#define MAX_TERMS 30 +#define MIN_DIVISOR 1.0e-10 +#define MAX_ERROR 1.0e-20 + +static int +greatest_common_divisor (int a, + int b) +{ + while (b != 0) + { + int temp = a; + + a = b; + b = temp % b; + } + + return ABS (a); +} + +MetaFraction +meta_fraction_from_double (double src) +{ + double V, F; /* double being converted */ + int N, D; /* will contain the result */ + int A; /* current term in continued fraction */ + int64_t N1, D1; /* numerator, denominator of last approx */ + int64_t N2, D2; /* numerator, denominator of previous approx */ + int i; + int gcd; + gboolean negative = FALSE; + + /* initialize fraction being converted */ + F = src; + if (F < 0.0) + { + F = -F; + negative = TRUE; + } + + V = F; + /* initialize fractions with 1/0, 0/1 */ + N1 = 1; + D1 = 0; + N2 = 0; + D2 = 1; + N = 1; + D = 1; + + for (i = 0; i < MAX_TERMS; i++) + { + /* get next term */ + A = (gint) F; /* no floor() needed, F is always >= 0 */ + /* get new divisor */ + F = F - A; + + /* calculate new fraction in temp */ + N2 = N1 * A + N2; + D2 = D1 * A + D2; + + /* guard against overflow */ + if (N2 > G_MAXINT || D2 > G_MAXINT) + break; + + N = N2; + D = D2; + + /* save last two fractions */ + N2 = N1; + D2 = D1; + N1 = N; + D1 = D; + + /* quit if dividing by zero or close enough to target */ + if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) + break; + + /* Take reciprocal */ + F = 1 / F; + } + + /* fix for overflow */ + if (D == 0) + { + N = G_MAXINT; + D = 1; + } + + /* fix for negative */ + if (negative) + N = -N; + + /* simplify */ + gcd = greatest_common_divisor (N, D); + if (gcd) + { + N /= gcd; + D /= gcd; + } + + return (MetaFraction) { + .num = N, + .denom = D + }; +} diff --git a/src/core/meta-fraction.h b/src/core/meta-fraction.h new file mode 100644 index 000000000..f7ab294cd --- /dev/null +++ b/src/core/meta-fraction.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_FRACTION_H +#define META_FRACTION_H + +typedef struct _MetaFraction +{ + int num; + int denom; +} MetaFraction; + +MetaFraction meta_fraction_from_double (double src); + +#endif /* META_FRACTION_H */