msvcrt: improve accuracy of exp/pow/cosh and sinh

Zheng Chen chanchengcc at gmail.com
Sat Apr 4 11:40:51 CDT 2015


The default fpu_cw = 0x27f makes the exp/pow/cosh/sinh functions producing
less accurate results. This patch temporally changes fpu_cw to 0x37f in
these functions for more accurate results.

Thanks to Qian for his ideas.

This patch fixes parts of these two bugs: 37149, 37150
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20150405/d9553dee/attachment.html>
-------------- next part --------------
From 714f0311caccd858c10934005d4e46dca78aa8be Mon Sep 17 00:00:00 2001
From: Zheng Chen <ChanChengCC at gmail.com>
Date: Sat, 4 Apr 2015 10:52:43 +0000
Subject: [PATCH] msvcrt: improve accuracy of exp/pow/cosh and sinh

---
 dlls/msvcrt/math.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index 0cd69da..02d17cd 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -390,8 +390,17 @@ double CDECL MSVCRT_cos( double x )
  */
 double CDECL MSVCRT_cosh( double x )
 {
+  double z;
+  WORD precise_cw = 0x37f, pre_cw = 0x00;
+
   if (!isfinite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
-  return cosh(x);
+
+  __asm__ __volatile__( "fnstcw %0" : "=m" (pre_cw) );
+  __asm__ __volatile__( "fldcw %0" : : "m" (precise_cw) );
+  z = cosh(x);
+  __asm__ __volatile__( "fldcw %0" : : "m" (pre_cw) );
+
+  return z;
 }
 
 /*********************************************************************
@@ -400,7 +409,7 @@ double CDECL MSVCRT_cosh( double x )
 double CDECL MSVCRT_exp( double x )
 {
   if (isnan(x)) *MSVCRT__errno() = MSVCRT_EDOM;
-  return exp(x);
+  return expl(x);
 }
 
 /*********************************************************************
@@ -438,7 +447,12 @@ double CDECL MSVCRT_log10( double x )
 double CDECL MSVCRT_pow( double x, double y )
 {
   /* FIXME: If x < 0 and y is not integral, set EDOM */
-  double z = pow(x,y);
+  double z;
+  WORD precise_cw = 0x37f, pre_cw = 0x00;
+  __asm__ __volatile__( "fnstcw %0" : "=m" (pre_cw) );
+  __asm__ __volatile__( "fldcw %0" : : "m" (precise_cw) );
+  z = pow(x,y);
+  __asm__ __volatile__( "fldcw %0" : : "m" (pre_cw) );
   if (!isfinite(z)) *MSVCRT__errno() = MSVCRT_EDOM;
   return z;
 }
@@ -457,8 +471,17 @@ double CDECL MSVCRT_sin( double x )
  */
 double CDECL MSVCRT_sinh( double x )
 {
+  double z;
+  WORD precise_cw = 0x37f, pre_cw = 0x00;
+
   if (!isfinite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
-  return sinh(x);
+
+  __asm__ __volatile__( "fnstcw %0" : "=m" (pre_cw) );
+  __asm__ __volatile__( "fldcw %0" : : "m" (precise_cw) );
+  z = sinh(x);
+  __asm__ __volatile__( "fldcw %0" : : "m" (pre_cw) );
+
+  return z;
 }
 
 /*********************************************************************
@@ -2080,7 +2103,7 @@ void __cdecl __libm_sse2_exp(void)
 {
     double d;
     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
-    d = exp( d );
+    d = expl( d );
     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
 }
 
@@ -2145,8 +2168,12 @@ void __cdecl __libm_sse2_logf(void)
 void __cdecl __libm_sse2_pow(void)
 {
     double d1, d2;
+    WORD precise_cw = 0x37f, pre_cw = 0x00;
     __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
+    __asm__ __volatile__( "fnstcw %0" : "=m" (pre_cw) );
+    __asm__ __volatile__( "fldcw %0" : : "m" (precise_cw) );
     d1 = pow( d1, d2 );
+    __asm__ __volatile__( "fldcw %0" : : "m" (pre_cw) );
     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
 }
 
-- 
2.3.3



More information about the wine-patches mailing list