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