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=67933&r1=67932&r2=67933&view=diff
==============================================================================
--- 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;
             }
 


Reply via email to