1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
47 // warning this code is used by amd64 and arm builds
53 const static double PI
= 3.141592653589793;
54 const static double PI3_BY_4
= 3*PI
/4;
55 const static double PI_BY_4
= PI
/4;
56 const static double PI2
= 2*PI
;
59 static int32_t isZero(double v
)
61 int32_t r
= (MathUtils::isNegZero(v
)) ? -1 : (v
==0.0)? 1 : 0;
65 // sin, cos, tan all function incorrectly when called with really large values on windows mobile
66 // they all start failing at different values, but all start failing somewhere with values
67 // greater than 210 million.
68 #define AVMPLUS_TRIG_FUNC_MAX 210000000
70 const static bool broken_trig_funcs
= MathUtils::isNaN(MathUtils::cos(250000000));
72 // Helper function to adjust a value for sin, cos, or tan into an equivalent value
73 // in the range that works correctly. This works because these functions all have a period
74 // of 2*PI or PI, so there are many equivalent values.
75 static double adjustValueForTrigFuncs(double v
)
83 int temp
= (int)((v
- AVMPLUS_TRIG_FUNC_MAX
)/PI2
);
84 double offset
= PI2
*(temp
+1);
93 #endif /* AVMPLUS_ARM */
96 double MathUtils::atan2(double y
, double x
)
98 int32_t zx
= isZero(x
);
99 int32_t zy
= isZero(y
);
101 return zy
*PI
; // +-0,-0 case
102 else if (zy
==-1 && (x
==1.0 || x
==-1.0))
103 return -(::atan2(y
,x
)); // negate result
105 double r
= ::atan2(y
, x
);
106 if (MathUtils::isNaN(r
)) {
107 int32_t s
= MathUtils::isInfinite(x
);
109 r
= MathUtils::isInfinite(y
) * PI_BY_4
;
111 r
= MathUtils::isInfinite(y
) * PI3_BY_4
;
115 #endif /* AVMPLUS_ARM */
118 double MathUtils::ceil(double value
)
120 // todo avoid control word modification
123 _asm mov ax
, [oldcw
];
124 _asm
and ax
, 0xf3ff; // Set to round down.
126 _asm mov
[newcw
], ax
;
132 #endif /* X86_MATH */
135 double MathUtils::cos(double value
)
137 if( broken_trig_funcs
&& (value
> AVMPLUS_TRIG_FUNC_MAX
|| value
< -AVMPLUS_TRIG_FUNC_MAX
) )
139 return ::cos(adjustValueForTrigFuncs(value
));
149 // Utility function, this module only.
150 REALLY_INLINE
static double expInternal(double x
)
152 double value
, exponent
;
155 _asm _emit
0xD8; // fmul st(1);
157 _asm _emit
0xDD; // fst st(1);
161 _asm _emit
0xD8; // fsub st1;
165 _asm fstp
[exponent
];
174 _asm _emit
0xDD; // fstp st(0);
178 // Inlined on other architectures
179 double MathUtils::exp(double value
)
181 switch (isInfinite(value
)) {
187 return expInternal(value
);
190 #endif /* X86_MATH */
193 double MathUtils::floor(double value
)
195 // todo avoid control word modification
198 _asm mov ax
, [oldcw
];
199 _asm
and ax
, 0xf3ff; // Set to round down.
201 _asm mov
[newcw
], ax
;
207 #endif /* X86_MATH */
209 /* @(#)s_frexp.c 5.1 93/09/24 */
211 * ====================================================
212 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
214 * Developed at SunPro, a Sun Microsystems, Inc. business.
215 * Permission to use, copy, modify, and distribute this
216 * software is freely granted, provided that this notice
218 * ====================================================
223 * x = frexp(arg,&exp);
224 * return a double fp quantity x such that 0.5 <= |x| <1.0
225 * and the corresponding binary exponent "exp". That is
227 * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
232 * NOTE: This is little-endian, must be adjusted to work for
233 * big-endian systems.
235 #define EXTRACT_WORDS(hx, lx, x) {DWORD *ptr = (DWORD*)&x; hx=ptr[1]; lx=ptr[0];}
236 #define SET_HIGH_WORD(x, hx) {DWORD *ptr = (DWORD*)&x; ptr[1]=hx;}
237 #define GET_HIGH_WORD(hx, x) {DWORD *ptr = (DWORD*)&x; hx=ptr[1];}
238 static const double two54
= 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
240 REALLY_INLINE
static double ExtractFraction(double x
, int *eptr
)
243 EXTRACT_WORDS(hx
,lx
,x
);
246 if(ix
>=0x7ff00000||((ix
|lx
)==0)) return x
; /* 0,inf,nan */
247 if (ix
<0x00100000) { /* subnormal */
253 *eptr
+= (ix
>>20)-1022;
254 hx
= (hx
&0x800fffff)|0x3fe00000;
259 uint64_t MathUtils::frexp(double x
, int *eptr
)
261 double fracMantissa
= ExtractFraction(x
, eptr
);
262 // correct mantissa and eptr to get integer values
264 *eptr
-= 53; // 52 mantissa bits + the hidden bit
265 return (uint64_t)((fracMantissa
) * (double)(1LL << 53));
269 // VC++ 2008 refuses to inline this, issues warning on _forceinline
270 #pragma warning ( disable : 4740 ) // flow in or out of inline asm code suppresses global optimization
271 double MathUtils::mod(double x
, double y
)
283 _asm _emit
0xDD; // fstp st(1);
286 #pragma warning ( default : 4740 )
287 #endif /* X86_MATH */
290 // Std. library pow()
291 double MathUtils::powInternal(double x
, double y
)
293 double value
, exponent
;
302 _asm _emit
0xD8; // fmul st(1);
304 _asm _emit
0xDD; // fst st(1);
308 _asm _emit
0xD8; // fsub st1;
312 _asm fstp
[exponent
];
321 _asm _emit
0xDD; // fstp st(0);
324 #endif /* X86_MATH */
327 double MathUtils::sin(double value
)
329 if( broken_trig_funcs
&& (value
> AVMPLUS_TRIG_FUNC_MAX
|| value
< -AVMPLUS_TRIG_FUNC_MAX
) )
331 return ::sin(adjustValueForTrigFuncs(value
));
338 #endif /* AVMPLUS_ARM */
341 double MathUtils::tan(double value
)
343 // This is a good candidate for inlining, but VC++ 2008 chokes on it.
346 _asm _emit
0xDD; // fstp st(0);
349 #elif defined(AVMPLUS_ARM)
350 double MathUtils::tan(double value
)
352 if( broken_trig_funcs
&& (value
> AVMPLUS_TRIG_FUNC_MAX
|| value
< -AVMPLUS_TRIG_FUNC_MAX
) )
354 return ::tan(adjustValueForTrigFuncs(value
));
361 #endif /* X86_MATH */