Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #ifndef nsMathUtils_h__ |
michael@0 | 7 | #define nsMathUtils_h__ |
michael@0 | 8 | |
michael@0 | 9 | #define _USE_MATH_DEFINES /* needed for M_ constants on Win32 */ |
michael@0 | 10 | |
michael@0 | 11 | #include "nscore.h" |
michael@0 | 12 | #include <cmath> |
michael@0 | 13 | #include <float.h> |
michael@0 | 14 | |
michael@0 | 15 | #ifdef SOLARIS |
michael@0 | 16 | #include <ieeefp.h> |
michael@0 | 17 | #endif |
michael@0 | 18 | |
michael@0 | 19 | /* |
michael@0 | 20 | * round |
michael@0 | 21 | */ |
michael@0 | 22 | inline NS_HIDDEN_(double) NS_round(double x) |
michael@0 | 23 | { |
michael@0 | 24 | return x >= 0.0 ? floor(x + 0.5) : ceil(x - 0.5); |
michael@0 | 25 | } |
michael@0 | 26 | inline NS_HIDDEN_(float) NS_roundf(float x) |
michael@0 | 27 | { |
michael@0 | 28 | return x >= 0.0f ? floorf(x + 0.5f) : ceilf(x - 0.5f); |
michael@0 | 29 | } |
michael@0 | 30 | inline NS_HIDDEN_(int32_t) NS_lround(double x) |
michael@0 | 31 | { |
michael@0 | 32 | return x >= 0.0 ? int32_t(x + 0.5) : int32_t(x - 0.5); |
michael@0 | 33 | } |
michael@0 | 34 | |
michael@0 | 35 | /* NS_roundup30 rounds towards infinity for positive and */ |
michael@0 | 36 | /* negative numbers. */ |
michael@0 | 37 | |
michael@0 | 38 | #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) |
michael@0 | 39 | inline NS_HIDDEN_(int32_t) NS_lroundup30(float x) |
michael@0 | 40 | { |
michael@0 | 41 | /* Code derived from Laurent de Soras' paper at */ |
michael@0 | 42 | /* http://ldesoras.free.fr/doc/articles/rounding_en.pdf */ |
michael@0 | 43 | |
michael@0 | 44 | /* Rounding up on Windows is expensive using the float to */ |
michael@0 | 45 | /* int conversion and the floor function. A faster */ |
michael@0 | 46 | /* approach is to use f87 rounding while assuming the */ |
michael@0 | 47 | /* default rounding mode of rounding to the nearest */ |
michael@0 | 48 | /* integer. This rounding mode, however, actually rounds */ |
michael@0 | 49 | /* to the nearest integer so we add the floating point */ |
michael@0 | 50 | /* number to itself and add our rounding factor before */ |
michael@0 | 51 | /* doing the conversion to an integer. We then do a right */ |
michael@0 | 52 | /* shift of one bit on the integer to divide by two. */ |
michael@0 | 53 | |
michael@0 | 54 | /* This routine doesn't handle numbers larger in magnitude */ |
michael@0 | 55 | /* than 2^30 but this is fine for NSToCoordRound because */ |
michael@0 | 56 | /* Coords are limited to 2^30 in magnitude. */ |
michael@0 | 57 | |
michael@0 | 58 | static const double round_to_nearest = 0.5f; |
michael@0 | 59 | int i; |
michael@0 | 60 | |
michael@0 | 61 | __asm { |
michael@0 | 62 | fld x ; load fp argument |
michael@0 | 63 | fadd st, st(0) ; double it |
michael@0 | 64 | fadd round_to_nearest ; add the rounding factor |
michael@0 | 65 | fistp dword ptr i ; convert the result to int |
michael@0 | 66 | } |
michael@0 | 67 | return i >> 1; /* divide by 2 */ |
michael@0 | 68 | } |
michael@0 | 69 | #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */ |
michael@0 | 70 | |
michael@0 | 71 | inline NS_HIDDEN_(int32_t) NS_lroundf(float x) |
michael@0 | 72 | { |
michael@0 | 73 | return x >= 0.0f ? int32_t(x + 0.5f) : int32_t(x - 0.5f); |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | /* |
michael@0 | 77 | * hypot. We don't need a super accurate version of this, if a platform |
michael@0 | 78 | * turns up with none of the possibilities below it would be okay to fall |
michael@0 | 79 | * back to sqrt(x*x + y*y). |
michael@0 | 80 | */ |
michael@0 | 81 | inline NS_HIDDEN_(double) NS_hypot(double x, double y) |
michael@0 | 82 | { |
michael@0 | 83 | #ifdef __GNUC__ |
michael@0 | 84 | return __builtin_hypot(x, y); |
michael@0 | 85 | #elif defined _WIN32 |
michael@0 | 86 | return _hypot(x, y); |
michael@0 | 87 | #else |
michael@0 | 88 | return hypot(x, y); |
michael@0 | 89 | #endif |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | /** |
michael@0 | 93 | * Check whether a floating point number is finite (not +/-infinity and not a |
michael@0 | 94 | * NaN value). |
michael@0 | 95 | */ |
michael@0 | 96 | inline NS_HIDDEN_(bool) NS_finite(double d) |
michael@0 | 97 | { |
michael@0 | 98 | #ifdef WIN32 |
michael@0 | 99 | // NOTE: '!!' casts an int to bool without spamming MSVC warning C4800. |
michael@0 | 100 | return !!_finite(d); |
michael@0 | 101 | #elif defined(XP_DARWIN) |
michael@0 | 102 | // Darwin has deprecated |finite| and recommends |isfinite|. The former is |
michael@0 | 103 | // not present in the iOS SDK. |
michael@0 | 104 | return std::isfinite(d); |
michael@0 | 105 | #else |
michael@0 | 106 | return finite(d); |
michael@0 | 107 | #endif |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | /** |
michael@0 | 111 | * Returns the result of the modulo of x by y using a floored division. |
michael@0 | 112 | * fmod(x, y) is using a truncated division. |
michael@0 | 113 | * The main difference is that the result of this method will have the sign of |
michael@0 | 114 | * y while the result of fmod(x, y) will have the sign of x. |
michael@0 | 115 | */ |
michael@0 | 116 | inline NS_HIDDEN_(double) NS_floorModulo(double x, double y) |
michael@0 | 117 | { |
michael@0 | 118 | return (x - y * floor(x / y)); |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | #endif |