Author: aandrejevic
Date: Wed May 27 01:00:20 2015
New Revision: 67933
URL:
http://svn.reactos.org/svn/reactos?rev=67933&view=rev
Log:
[FAST486]
Implement FPATAN.
Fix the sign of the FPTAN result. Spotted by fox_anthony.
Modified:
trunk/reactos/lib/fast486/fpu.c
Modified: trunk/reactos/lib/fast486/fpu.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=6793…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Wed May 27 01:00:20 2015
@@ -221,6 +221,60 @@
{0xD3D56292AB7E800DULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9900 */
};
+static const FAST486_FPU_DATA_REG FpuInverseNumberAtan[INVERSE_NUMBERS_COUNT] =
+{
+ {0xAAAAAAAAAAAAAAAAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 2 / 3 */
+ {0xCCCCCCCCCCCCCCCCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 4 / 5 */
+ {0xDB6DB6DB6DB6DB6DULL, FPU_REAL10_BIAS - 1, FALSE}, /* 6 / 7 */
+ {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 8 / 9 */
+ {0xE8BA2E8BA2E8BA2EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 10 / 11 */
+ {0xEC4EC4EC4EC4EC4EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 12 / 13 */
+ {0xEEEEEEEEEEEEEEEEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 14 / 15 */
+ {0xF0F0F0F0F0F0F0F0ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 16 / 17 */
+ {0xF286BCA1AF286BCAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 18 / 19 */
+ {0xF3CF3CF3CF3CF3CFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 20 / 21 */
+ {0xF4DE9BD37A6F4DE9ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 22 / 23 */
+ {0xF5C28F5C28F5C28FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 24 / 25 */
+ {0xF684BDA12F684BDAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 26 / 27 */
+ {0xF72C234F72C234F7ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 28 / 29 */
+ {0xF7BDEF7BDEF7BDEFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 30 / 31 */
+ {0xF83E0F83E0F83E0FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 32 / 33 */
+ {0xF8AF8AF8AF8AF8AFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 34 / 35 */
+ {0xF914C1BACF914C1BULL, FPU_REAL10_BIAS - 1, FALSE}, /* 36 / 37 */
+ {0xF96F96F96F96F96FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 38 / 39 */
+ {0xF9C18F9C18F9C18FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 40 / 41 */
+ {0xFA0BE82FA0BE82FAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 42 / 43 */
+ {0xFA4FA4FA4FA4FA4FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 44 / 45 */
+ {0xFA8D9DF51B3BEA36ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 46 / 47 */
+ {0xFAC687D6343EB1A1ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 48 / 49 */
+ {0xFAFAFAFAFAFAFAFAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 50 / 51 */
+ {0xFB2B78C13521CFB2ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 52 / 53 */
+ {0xFB586FB586FB586FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 54 / 55 */
+ {0xFB823EE08FB823EEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 56 / 57 */
+ {0xFBA9386822B63CBEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 58 / 59 */
+ {0xFBCDA3AC10C9714FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 60 / 61 */
+ {0xFBEFBEFBEFBEFBEFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 62 / 63 */
+ {0xFC0FC0FC0FC0FC0FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 64 / 65 */
+ {0xFC2DD9CA81E9131AULL, FPU_REAL10_BIAS - 1, FALSE}, /* 66 / 67 */
+ {0xFC4A33F128CFC4A3ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 68 / 69 */
+ {0xFC64F52EDF8C9EA5ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 70 / 71 */
+ {0xFC7E3F1F8FC7E3F1ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 72 / 73 */
+ {0xFC962FC962FC962FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 74 / 75 */
+ {0xFCACE213F2B3884FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 76 / 77 */
+ {0xFCC26E2D5DF984DCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 78 / 79 */
+ {0xFCD6E9E06522C3F3ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 80 / 81 */
+ {0xFCEA68DE12818ACBULL, FPU_REAL10_BIAS - 1, FALSE}, /* 82 / 83 */
+ {0xFCFCFCFCFCFCFCFCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 84 / 85 */
+ {0xFD0EB66FD0EB66FDULL, FPU_REAL10_BIAS - 1, FALSE}, /* 86 / 87 */
+ {0xFD1FA3F47E8FD1FAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 88 / 89 */
+ {0xFD2FD2FD2FD2FD2FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 90 / 91 */
+ {0xFD3F4FD3F4FD3F4FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 92 / 93 */
+ {0xFD4E25B9EFD4E25BULL, FPU_REAL10_BIAS - 1, FALSE}, /* 94 / 95 */
+ {0xFD5C5F02A3A0FD5CULL, FPU_REAL10_BIAS - 1, FALSE}, /* 96 / 97 */
+ {0xFD6A052BF5A814AFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 98 / 99 */
+ {0xFD7720F353A4C0A2ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 100 / 101 */
+};
+
/* PRIVATE FUNCTIONS **********************************************************/
#ifndef FAST486_NO_FPU
@@ -1313,7 +1367,7 @@
PCFAST486_FPU_DATA_REG FirstOperand,
PCFAST486_FPU_DATA_REG SecondOperand,
BOOLEAN RoundToNearest,
- PFAST486_FPU_DATA_REG Result,
+ PFAST486_FPU_DATA_REG Result OPTIONAL,
PLONGLONG Quotient OPTIONAL)
{
BOOLEAN Success = FALSE;
@@ -1326,10 +1380,13 @@
State->FpuControl.Rc = RoundToNearest ? FPU_ROUND_NEAREST : FPU_ROUND_TRUNCATE;
if (!Fast486FpuToInteger(State, &Temp, &Integer)) goto Cleanup;
- Fast486FpuFromInteger(State, Integer, &Temp);
-
- if (!Fast486FpuMultiply(State, &Temp, SecondOperand, &Temp)) goto Cleanup;
- if (!Fast486FpuSubtract(State, FirstOperand, &Temp, Result)) goto Cleanup;
+
+ if (Result)
+ {
+ Fast486FpuFromInteger(State, Integer, &Temp);
+ if (!Fast486FpuMultiply(State, &Temp, SecondOperand, &Temp)) goto
Cleanup;
+ if (!Fast486FpuSubtract(State, FirstOperand, &Temp, Result)) goto Cleanup;
+ }
if (Quotient) *Quotient = Integer;
Success = TRUE;
@@ -1562,6 +1619,123 @@
return TRUE;
}
+/*
+ * Calculates arctan using Euler's formula:
+ * arctan(x) = (x / (1 + x^2)) * sum { prod { (2j * x^2)
+ * / ((2j + 1) * (1 + x^2)), j >= 1, j <= i }, i >= 0 }
+ */
+static inline BOOLEAN FASTCALL
+Fast486FpuCalculateArcTangent(PFAST486_STATE State,
+ PCFAST486_FPU_DATA_REG Numerator,
+ PCFAST486_FPU_DATA_REG Denominator,
+ PFAST486_FPU_DATA_REG Result)
+{
+ INT i;
+ BOOLEAN Inverted = FALSE;
+ FAST486_FPU_DATA_REG TempNumerator = *Numerator;
+ FAST486_FPU_DATA_REG TempDenominator = *Denominator;
+ FAST486_FPU_DATA_REG Value;
+ FAST486_FPU_DATA_REG TempResult;
+ FAST486_FPU_DATA_REG ValDivValSqP1;
+ FAST486_FPU_DATA_REG SeriesElement = FpuOne;
+
+ TempNumerator.Sign = FALSE;
+ TempDenominator.Sign = FALSE;
+
+ /* Compare the numerator to the denominator */
+ if (!Fast486FpuSubtract(State, &TempNumerator, &TempDenominator,
&TempResult))
+ {
+ return FALSE;
+ }
+
+ if ((Inverted = !TempResult.Sign))
+ {
+ if (!Fast486FpuDivide(State, &TempDenominator, &TempNumerator,
&Value))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!Fast486FpuDivide(State, &TempNumerator, &TempDenominator,
&Value))
+ {
+ return FALSE;
+ }
+ }
+
+ /* Apparently, atan2(0, 0) = +/- 0 or +/- pi for some reason... */
+ if (FPU_IS_INDEFINITE(&Value)) Value = FpuZero;
+
+ /* Calculate the value divided by the value squared plus one */
+ if (!Fast486FpuMultiply(State, &Value, &Value, &ValDivValSqP1)) return
FALSE;
+ if (!Fast486FpuAdd(State, &ValDivValSqP1, &FpuOne, &ValDivValSqP1))
return FALSE;
+ if (!Fast486FpuDivide(State, &Value, &ValDivValSqP1, &ValDivValSqP1))
return FALSE;
+
+ TempResult = FpuOne;
+
+ for (i = 0; i < INVERSE_NUMBERS_COUNT; i++)
+ {
+ if (!Fast486FpuMultiply(State, &SeriesElement, &Value,
&SeriesElement))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (!Fast486FpuMultiply(State, &SeriesElement, &ValDivValSqP1,
&SeriesElement))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (!Fast486FpuMultiply(State,
+ &SeriesElement,
+ &FpuInverseNumberAtan[i],
+ &SeriesElement))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (!Fast486FpuAdd(State, &TempResult, &SeriesElement, &TempResult))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+ }
+
+ if (!Fast486FpuMultiply(State, &TempResult, &ValDivValSqP1,
&TempResult))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (Inverted)
+ {
+ /* Since y/x is positive, arctan(y/x) = pi/2 - arctan(x/y) */
+ if (!Fast486FpuSubtract(State, &FpuHalfPi, &TempResult, &TempResult))
return FALSE;
+ }
+
+ /* Adjust the sign */
+ if (!(!Numerator->Sign == !Denominator->Sign)) TempResult.Sign =
!TempResult.Sign;
+
+ if (Denominator->Sign)
+ {
+ if (Numerator->Sign)
+ {
+ /* Subtract PI */
+ if (!Fast486FpuSubtract(State, &TempResult, &FpuPi, &TempResult))
return FALSE;
+ }
+ else
+ {
+ /* Add PI */
+ if (!Fast486FpuAdd(State, &TempResult, &FpuPi, &TempResult))
return FALSE;
+ }
+ }
+
+ *Result = TempResult;
+ return TRUE;
+}
+
static inline BOOLEAN FASTCALL
Fast486FpuLoadEnvironment(PFAST486_STATE State,
INT Segment,
@@ -2138,15 +2312,33 @@
{
FAST486_FPU_DATA_REG Sine;
FAST486_FPU_DATA_REG Cosine;
+ ULONGLONG Quadrant;
/* Compute the sine */
if (!Fast486FpuCalculateSine(State, &FPU_ST(0), &Sine)) break;
+
+ /* Normalize the angle */
+ if (!Fast486FpuRemainder(State,
+ &FPU_ST(0),
+ &FpuHalfPi,
+ FALSE,
+ NULL,
+ (PLONGLONG)&Quadrant))
+ {
+ break;
+ }
+
+ /* Normalize the quadrant number */
+ Quadrant &= 3;
/* Find the cosine by calculating sqrt(1 - sin(x) ^ 2) */
if (!Fast486FpuMultiply(State, &Sine, &Sine, &Cosine))
break;
if (!Fast486FpuSubtract(State, &FpuOne, &Cosine, &Cosine))
break;
if (!Fast486FpuCalculateSquareRoot(State, &Cosine, &Cosine))
break;
+ /* Adjust the sign of the cosine */
+ if (Quadrant == 1 || Quadrant == 2) Cosine.Sign = TRUE;
+
/* Divide the sine by the cosine to get the tangent */
if (!Fast486FpuDivide(State, &Sine, &Cosine, &FPU_ST(0)))
break;
FPU_UPDATE_TAG(0);
@@ -2159,9 +2351,17 @@
/* FPATAN */
case 0x33:
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
+ if (!Fast486FpuCalculateArcTangent(State,
+ &FPU_ST(1),
+ &FPU_ST(0),
+ &FPU_ST(1)))
+ {
+ break;
+ }
+
+ FPU_UPDATE_TAG(1);
+
+ Fast486FpuPop(State);
break;
}