fp.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,429 行 · 第 1/3 页

C
1,429
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


/* This module contains floating point functions that conform to the Java 1.3
 * standard.  This standard is close to the IEEE754 standard but there are
 * some differences.
 */
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include "mp.h"
#include "fp.h"

#define FALSE 0
#define TRUE 1

#define SET_CW_ROUND_TO_NEAREST \
        "push 0000037FH" \
        "fldcw dword ptr [esp]" \
        "add esp,4"

#define SET_CW_ROUND_TO_ZERO \
        "push 00000F7FH" \
        "fldcw dword ptr [esp]" \
        "add esp,4"

void c_dadd( void *dst, void *src1, void *src2 );
void c_dsub( void *dst, void *src1, void *src2 );

#ifndef C_IMPL
void _dadd( void *, void *, void * );
#pragma aux     _dadd = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fld qword ptr [ebx]" \
        "fadd" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void dadd( void *dst, void *src1, void *src2 ) {
    uint64 f1, f2;
    int e1, e2;
    int diff;

    parseDouble( *(double*)src1, &f1, &e1 );
    parseDouble( *(double*)src2, &f2, &e2 );
    diff = abs( (e1 - e2) );
    if( diff > 11 && diff <= 53 ) {
        /* the FPU will round twice during this operation so use the c version
         * of this function instead */
        c_dadd( dst, src1, src2 );
    } else {
        _dadd( dst, src1, src2 );
    }
}

void _dsub( void *, void *, void * );
#pragma aux     _dsub = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fsub qword ptr [ebx]" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void dsub( void *dst, void *src1, void *src2 ) {
    uint64 f1, f2;
    int e1, e2;
    int diff;

    parseDouble( *(double*)src1, &f1, &e1 );
    parseDouble( *(double*)src2, &f2, &e2 );
    diff = abs( (e1 - e2) );
    if( diff > 11 && diff <= 53 ) {
        /* the FPU will round twice during this operation so use the c version
         * of this function instead */
        c_dsub( dst, src1, src2 );
    } else {
        _dsub( dst, src1, src2 );
    }
}

void _dmul( void *, void *, void * );
#pragma aux     _dmul = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fmul qword ptr [ebx]" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void dmul( void *dst, void *src1, void *src2 ) {
    _dmul( dst, src1, src2 );
}

void _ddiv( void *, void *, void * );
#pragma aux     _ddiv = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fdiv qword ptr [ebx]" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void ddiv( void *dst, void *src1, void *src2 ) {
    _ddiv( dst, src1, src2 );
}

void _drem( void *, void *, void * );
#pragma aux     _drem = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [ebx]" \
        "fld qword ptr [edx]" \
        "mov ecx,eax" \
        "remloop:" \
        "fprem" \
        "fstsw ax" \
        "test ax,0400H" \
        "jne remloop" \
        "mov eax,ecx" \
        "fstp qword ptr [eax]" \
        "fstp qword ptr [ebx]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [ecx];
void drem( void *dst, void *src1, void *src2 ) {
    _drem( dst, src1, src2 );
}

void _dneg( void *, void * );
#pragma aux     _dneg = \
        "fld qword ptr [edx]" \
        "fchs" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void dneg( void *dst, void *src ) {
    _dneg( dst, src );
}

void _fadd( void *, void *, void * );
#pragma aux     _fadd = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fadd dword ptr [ebx]" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void fadd( void *dst, void *src1, void *src2 ) {
    _fadd( dst, src1, src2 );
}

void _fsub( void *, void *, void * );
#pragma aux     _fsub = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fsub dword ptr [ebx]" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void fsub( void *dst, void *src1, void *src2 ) {
    _fsub( dst, src1, src2 );
}

void _fmul( void *, void *, void * );
#pragma aux     _fmul = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fld dword ptr [ebx]" \
        "fmul" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void fmul( void *dst, void *src1, void *src2 ) {
    _fmul( dst, src1, src2 );
}

void _fdiv( void *, void *, void * );
#pragma aux     _fdiv = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fld dword ptr [ebx]" \
        "fdiv" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void fdiv( void *dst, void *src1, void *src2 ) {
    _fdiv( dst, src1, src2 );
}

void _frem( void *, void *, void * );
#pragma aux     _frem = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [ebx]" \
        "fld dword ptr [edx]" \
        "mov ecx,eax" \
        "remloop:" \
        "fprem" \
        "fstsw ax" \
        "test ax,0400H" \
        "jne remloop" \
        "mov eax,ecx" \
        "fstp dword ptr [eax]" \
        "fstp dword ptr [ebx]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [ecx];
void frem( void *dst, void *src1, void *src2 ) {
    _frem( dst, src1, src2 );
}

void _fneg( void *, void * );
#pragma aux     _fneg = \
        "fld dword ptr [edx]" \
        "fchs" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void fneg( void *dst, void *src ) {
    _fneg( dst, src );
}

void _eadd( void *, void *, void * );
#pragma aux     _eadd = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [edx]" \
        "fld tbyte ptr [ebx]" \
        "fadd" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void eadd( void *dst, void *src1, void *src2 ) {
    _eadd( dst, src1, src2 );
}

void _esub( void *, void *, void * );
#pragma aux     _esub = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [edx]" \
        "fld tbyte ptr [edx]" \
        "fsub" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void esub( void *dst, void *src1, void *src2 ) {
    _esub( dst, src1, src2 );
}

void _emul( void *, void *, void * );
#pragma aux     _emul = \
        SET_CW_ROUND_TO_NEAREST \
        "finit" \
        "fld tbyte ptr [edx]" \
        "fld tbyte ptr [ebx]" \
        "fmul" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void emul( void *dst, void *src1, void *src2 ) {
    _emul( dst, src1, src2 );
}

void _ediv( void *, void *, void * );
#pragma aux     _ediv = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [edx]" \
        "fld tbyte ptr [ebx]" \
        "fdiv" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [];
void ediv( void *dst, void *src1, void *src2 ) {
    _ediv( dst, src1, src2 );
}

void _erem( void *, void *, void * );
#pragma aux     _erem = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [ebx]" \
        "fld tbyte ptr [edx]" \
        "mov ecx,eax" \
        "remloop:" \
        "fprem" \
        "fstsw ax" \
        "test ax,0400H" \
        "jne remloop" \
        "mov eax,ecx" \
        "fstp tbyte ptr [eax]" \
        "fstp tbyte ptr [ebx]" \
        parm caller [eax] [edx] [ebx] \
        modify exact [ecx];
void erem( void *dst, void *src1, void *src2 ) {
    _erem( dst, src1, src2 );
}

void _eneg( void *, void * );
#pragma aux     _eneg = \
        "fld tbyte ptr [edx]" \
        "fchs" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void eneg( void *dst, void *src ) {
    _eneg( dst, src );
}

/****** conversion functions **********/

void _f2d( void *, void * );
#pragma aux     _f2d = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [ebx];
void f2d( void *dst, void *src ) {
    _f2d( dst, src );
}

void _d2f( void *, void * );
#pragma aux     _d2f = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [ebx];
void d2f( void *dst, void *src ) {
    _d2f( dst, src );
}

void _e2d( void *, void * );
#pragma aux     _e2d = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [edx]" \
        "fstp qword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void e2d( void *dst, void *src ) {
    _e2d( dst, src );
}

void _d2e( void *, void * );
#pragma aux     _d2e = \
        SET_CW_ROUND_TO_NEAREST \
        "fld qword ptr [edx]" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void d2e( void *dst, void *src ) {
    _d2e( dst, src );
}

void _e2f( void *, void * );
#pragma aux     _e2f = \
        SET_CW_ROUND_TO_NEAREST \
        "fld tbyte ptr [edx]" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void e2f( void *dst, void *src ) {
    _e2f( dst, src );
}

void _f2e( void *, void * );
#pragma aux     _f2e = \
        SET_CW_ROUND_TO_NEAREST \
        "fld dword ptr [edx]" \
        "fstp tbyte ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void f2e( void *dst, void *src ) {
    _f2e( dst, src );
}

void _f2i( void *, void * );
#pragma aux     _f2i = \
        SET_CW_ROUND_TO_ZERO \
        "fld dword ptr [edx]" \
        "mov ebx,eax" \
        "push 07FFFFFFFH" \
        "fild dword ptr [esp]" \
        "add esp,4" \
        "fcomp" \
        "fstsw ax" \
        "test ax,0400H" \
        "jnz nan" \
        "test ax,0100H" \
        "jnz large" \
        "mov eax,ebx" \
        "fist dword ptr [eax]" \
        "jmp done" \
        "nan:" \
        "mov eax,ebx" \
        "mov dword ptr [eax],0000H" \
        "jmp done" \
        "large:" \
        "mov eax,ebx" \
        "mov dword ptr [eax],7FFFFFFFH" \
        "done:" \
        "fstp dword ptr [edx]" \
        parm caller [eax] [edx] \
        modify exact [];
void f2i( void *dst, void *src ) {
    _f2i( dst, src );
}

void _i2f( void *, void * );
#pragma aux     _i2f = \
        SET_CW_ROUND_TO_NEAREST \
        "fild dword ptr [edx]" \
        "fstp dword ptr [eax]" \
        parm caller [eax] [edx] \
        modify exact [];
void i2f( void *dst, void *src ) {
    _i2f( dst, src );
}

void _f2l( void *, void * );
#pragma aux     _f2l = \
        SET_CW_ROUND_TO_ZERO \
        "fld dword ptr [edx]" \
        "mov ebx,eax" \
        "push 07FFFFFFFH" \
        "push 0FFFFFFFFH" \
        "fild qword ptr [esp]" \
        "add esp,8" \
        "fcomp" \
        "fstsw ax" \
        "test ax,0400H" \
        "jnz nan" \
        "test ax,0100H" \
        "jnz large" \
        "mov eax,ebx" \
        "fistp qword ptr [eax]" \
        "jmp done" \
        "nan:" \
        "mov eax,ebx" \
        "mov dword ptr [eax],0000H" \
        "mov dword ptr +4[eax],0000H" \
        "fstp dword ptr [edx]" \
        "jmp done" \
        "large:" \
        "mov eax,ebx" \
        "mov dword ptr [eax],0FFFFFFFFH" \
        "mov dword ptr +4[eax],07FFFFFFFH" \
        "fstp dword ptr [edx]" \
        "done:" \
        parm caller [eax] [edx] \
        modify exact [];
void f2l( void *dst, void *src ) {
    _f2l( dst, src );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?