[CRT] Implement portable ceil/floor

This commit is contained in:
Timo Kreuzer 2021-05-29 19:40:30 +02:00
parent 2943ea2cfe
commit 3aa3b3af56
7 changed files with 139 additions and 192 deletions

View file

@ -1,55 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Implementation of ceil
* FILE: lib/sdk/crt/math/amd64/ceil.S
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ksamd64.inc>
/* CODE **********************************************************************/
.code64
/* ceil(x) = - floor(-x)
*/
PUBLIC ceil
.PROC ceil
sub rsp, 16
.ENDPROLOG
/* Duplicate the bits into rax */
movd rax, xmm0
/* Invert the sign bit */
rol rax, 1
xor al, 1
ror rax, 1
/* Copy back to xmm0 */
movd xmm0, rax
/* Truncate xmm0 to integer (double precision) */
cvttsd2si rcx, xmm0
/* Shift all bits to the right, keeping the sign bit */
shr rax, 63
/* Substract the sign bit from the truncated value, so that
we get the correct result for negative values. */
sub rcx, rax
/* Now compensate for the previous negation */
neg rcx
/* Convert the result back to xmm0 (double precision) */
cvtsi2sd xmm0, rcx
add rsp, 16
ret
.ENDP
END

View file

@ -1,51 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Implementation of tan
* FILE: lib/sdk/crt/math/amd64/ceilf.S
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ksamd64.inc>
/* CODE **********************************************************************/
.code64
PUBLIC ceilf
FUNC ceilf
sub rsp, 16
.ENDPROLOG
/* Duplicate the bits into eax (zero exteneded to rax) */
movd eax, xmm0
/* Invert the sign bit */
xor eax, HEX(80000000)
/* Copy back to xmm0 */
movd xmm0, eax
/* Truncate xmm0 to integer (single precision) */
cvttss2si rcx, xmm0
/* Shift all bits to the right, keeping the sign bit */
shr rax, 31
/* Add the sign bit from the truncated value, so that
we get the correct result for negative values. */
add rcx, rax
/* Now compensate for the previous negation */
neg ecx
/* Convert the result back to xmm0 (single precision) */
cvtsi2ss xmm0, rcx
add rsp, 16
ret
ENDFUNC
END

View file

@ -1,41 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Implementation of floor
* FILE: lib/sdk/crt/math/amd64/floor.S
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
/* CODE **********************************************************************/
.code64
PUBLIC floor
FUNC floor
sub rsp, 16
.ENDPROLOG
/* Truncate xmm0 to integer (double precision) */
cvttsd2si rcx, xmm0
/* Duplicate the bits into rax */
movd rax, xmm0
/* Shift all bits to the right, keeping the sign bit */
shr rax, 63
/* Substract the sign bit from the truncated value, so that
we get the correct result for negative values. */
sub rcx, rax
/* Convert the result back to xmm0 (double precision) */
cvtsi2sd xmm0, rcx
add rsp, 16
ret
ENDFUNC
END

View file

@ -1,41 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Implementation of floorf
* FILE: lib/sdk/crt/math/amd64/floorf.S
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
/* CODE **********************************************************************/
.code64
PUBLIC floorf
FUNC floorf
sub rsp, 16
.ENDPROLOG
/* Truncate xmm0 to integer (single precision) */
cvttss2si rcx, xmm0
/* Duplicate the bits into rax */
movd eax, xmm0
/* Shift all bits to the right, keeping the sign bit */
shr rax, 31
/* Substract the sign bit from the truncated value, so that
we get the correct result for negative values. */
sub rcx, rax
/* Convert the result back to xmm0 (single precision) */
cvtsi2ss xmm0, rcx
add rsp, 16
ret
ENDFUNC
END

65
sdk/lib/crt/math/ceil.c Normal file
View file

@ -0,0 +1,65 @@
/*
* PROJECT: ReactOS CRT library
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Portable implementation of ceil
* COPYRIGHT: Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
*/
#define _USE_MATH_DEFINES
#include <math.h>
#include <limits.h>
#ifdef _MSC_VER
#pragma function(ceil)
#endif
double
__cdecl
ceil(double x)
{
/* Load the value as uint64 */
unsigned long long u64 = *(unsigned long long*)&x;
/* Check for NAN */
if ((u64 & ~(1ULL << 63)) > 0x7FF0000000000000ull)
{
/* Set error bit */
u64 |= 0x0008000000000000ull;
return *(double*)&u64;
}
/* Check if x is positive */
if ((u64 & (1ULL << 63)) == 0)
{
/* Check if it fits into an int64 */
if (x < (double)_I64_MAX)
{
/* Cast to int64 to truncate towards 0. If this matches the
input, return it as is, otherwise add 1 */
double y = (double)(long long)x;
return (x > y) ? y + 1 : y;
}
else
{
/* The exponent is larger than the fraction bits.
This means the number is already an integer. */
return x;
}
}
else
{
/* Check if it fits into an int64 */
if (x > (double)_I64_MIN)
{
/* Cast to int64 to truncate towards 0. */
x = (double)(long long)x;
return (x == 0.) ? -0.0 : x;
}
else
{
/* The exponent is larger than the fraction bits.
This means the number is already an integer. */
return x;
}
}
}

71
sdk/lib/crt/math/floor.c Normal file
View file

@ -0,0 +1,71 @@
/*
* PROJECT: ReactOS CRT library
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Implementation of floor
* COPYRIGHT: Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
*/
#define _USE_MATH_DEFINES
#include <math.h>
#include <limits.h>
#ifdef _MSC_VER
#pragma function(floor)
#endif
double
__cdecl
floor(double x)
{
/* Load the value as uint64 */
unsigned long long u64 = *(unsigned long long*)&x;
/* Check for NAN */
if ((u64 & ~(1ULL << 63)) > 0x7FF0000000000000ull)
{
/* Set error bit */
u64 |= 0x0008000000000000ull;
return *(double*)&u64;
}
/* Check if x is positive */
if ((u64 & (1ULL << 63)) == 0)
{
/* Check if it fits into an int64 */
if (x < (double)_I64_MAX)
{
/* Just cast to int64, which will truncate towards 0,
which is what we want here.*/
return (double)(long long)x;
}
else
{
/* The exponent is larger than the fraction bits.
This means the number is already an integer. */
return x;
}
}
else
{
/* Check if it fits into an int64 */
if (x > (double)_I64_MIN)
{
/* Check if it is -0 */
if (x == -0.)
{
return -0.;
}
/* Cast to int64 to truncate towards 0. If this matches the
input, return it as is, otherwise subtract 1 */
double y = (double)(long long)x;
return (x == y) ? y : y - 1;
}
else
{
/* The exponent is larger than the fraction bits.
This means the number is already an integer. */
return x;
}
}
}

View file

@ -53,18 +53,17 @@ if(ARCH STREQUAL "i386")
)
elseif(ARCH STREQUAL "amd64")
list(APPEND LIBCNTPR_MATH_SOURCE
math/ceil.c
math/cos.c
math/sin.c
math/floor.c
)
list(APPEND LIBCNTPR_MATH_ASM_SOURCE
math/amd64/atan.S
math/amd64/atan2.S
math/amd64/ceil.S
math/amd64/exp.S
math/amd64/fabs.S
math/amd64/fabsf.S
math/amd64/floor.S
math/amd64/floorf.S
math/amd64/fmod.S
math/amd64/ldexp.S
math/amd64/log.S
@ -78,7 +77,6 @@ elseif(ARCH STREQUAL "arm")
math/cos.c
math/fabs.c
math/fabsf.c
math/floorf.c
math/sin.c
math/sqrt.c
math/arm/__rt_sdiv.c
@ -131,6 +129,7 @@ if(NOT ARCH STREQUAL "i386")
math/cos.c
math/coshf.c
math/expf.c
math/floorf.c
math/fmodf.c
math/log10f.c
math/modff.c