int main () { double d, d1, d2; float f, f1, f2; unsigned long long ull, a, b; long long ll; int i; #ifdef __powerpc64__ ull = __rldcl (a, b, 3); ull = __rldcr (a, b, 3); ull = __rldic (a, 3, 4); ull = __rldicl (a, 4, 5); ull = __rldicr (a, 2, 3); ull = __rldimi (a, b, 4, 6); #endif ull = __rlwimi (a, b, 6, 9, 12); ull = __rlwnm (a, b, 3, 5); d = __fmul (d1, d2); f = __fmuls (f1, f2); f = __frsp (f); d = __fcfid (ll); d = __frsqrte (d1); ll = __fctid (d); ll = __fctidz (d); i = __fctiw (d); i = __fctiwz (d); __protected_stream_count (1, 2); __protected_stream_go (); __protected_stream_set (1, 0x1000, 3); __protected_stream_stop (3); __protected_stream_stop_all (); __protected_unlimited_stream_set (3, 0x1000, 1); return 0; }
static cell AMX_NATIVE_CALL n_fmul(AMX *amx,const cell *params) { #if !USE_ANSI_C #if defined __WATCOMC__ && defined __386__ cell __fmul(void); cell a=params[1]; cell b=params[2]; #if MULTIPLIER != 1000 #error Assembler chunks must be modified for a different base #endif #pragma aux __fmul = \ "mov eax, [a]" \ "mov ebx, 1000" \ "imul [b]" \ "add eax, 500" \ "adc edx, 0" \ "idiv ebx" \ "mov [a], eax" \ modify [eax ebx edx]; __fmul(); (void)amx; return a; #elif _MSC_VER>=9 && defined _WIN32 __int64 a=(__int64)params[1] * (__int64)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__) __int64 a=(__int64)params[1] * (__int64)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #elif defined __GNUC__ long long a=(long long)params[1] * (long long)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #else #error Unsupported compiler configuration, but USE_ANSI_C is false #endif #else // USE_ANSI_C /* (Xs * Ys) == (X*Y)ss, where "s" stands for scaled. * The desired result is (X*Y)s, so we must unscale once. * but we cannot do this before multiplication, because of loss * of precision, and we cannot do it after the multiplication * because of the possible overflow. * The technique used here is to cut the multiplicands into * components and to multiply these components separately: * * Assume Xs == (A << 16) + B and Ys == (C << 16) + D, where A, B, * C and D are 16 bit numbers. * * A B * C D * --- * * D*B + (D*A << 16) + (C*B << 16) + (C*A << (16+16)) * * Thus we have built a 64-bit number, which can now be scaled back * to 32-bit by dividing by the scale factor. */ #define ADD_WRAP(var,carry,expr) (((var)+=(expr)), ((carry)+=((var)<(expr)) ? 1 : 0)) ucell a,b,c,d; ucell v[2]; cell sign=1; (void)amx; assert(MULTIPLIER<=(1L<<WORDSHIFT)); /* make both operands positive values, but keep the sign of the result */ if (params[1]<0) { ((cell*)params)[1]=-params[1]; sign=-sign; /* negate result */ } /* if */ if (params[2]<0) { ((cell*)params)[2]=-params[2]; sign=-sign; /* negate result */ } /* if */ a = HIWORD(params[1]); b = LOWORD(params[1]); c = HIWORD(params[2]); d = LOWORD(params[2]); /* store the intermediate into a 64-bit/128-bit number */ v[1]=c*a; v[0]=d*b; ADD_WRAP(v[0],v[1],d*a << WORDSHIFT); ADD_WRAP(v[0],v[1],c*b << WORDSHIFT); /* add half of the divisor, to round the data */ ADD_WRAP(v[0],v[1],MULTIPLIER/2); /* if the divisor is smaller than v[1], the result will not fit in a cell */ if (MULTIPLIER<v[1]) { amx_RaiseError(amx,AMX_ERR_DOMAIN); return 0; } /* if */ return (cell)div64_32(v,MULTIPLIER) * sign; #endif }