11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ==================================================== 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Developed at SunPro, a Sun Microsystems, Inc. business. 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Permission to use, copy, modify, and distribute this 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * software is freely granted, provided that this notice 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * is preserved. 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ==================================================== 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * From: @(#)s_floor.c 5.1 93/09/24 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 14a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <sys/cdefs.h> 15a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes__FBSDID("$FreeBSD$"); 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * floorl(x) 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Return x rounded toward -inf to integral value 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Method: 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Bit twiddling. 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Exception: 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Inexact flag raised if x not equal to floorl(x). 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <float.h> 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <math.h> 281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdint.h> 291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "fpmath.h" 311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef LDBL_IMPLICIT_NBIT 331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MANH_SIZE (LDBL_MANH_SIZE + 1) 341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define INC_MANH(u, c) do { \ 351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint64_t o = u.bits.manh; \ 361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manh += (c); \ 371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.manh < o) \ 381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.exp++; \ 391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} while (0) 401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else 411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MANH_SIZE LDBL_MANH_SIZE 421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define INC_MANH(u, c) do { \ 431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint64_t o = u.bits.manh; \ 441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manh += (c); \ 451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.manh < o) { \ 461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.exp++; \ 471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \ 481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } \ 491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} while (0) 501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const long double huge = 1.0e300; 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectlong double 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfloorl(long double x) 561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project union IEEEl2bits u = { .e = x }; 581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int e = u.bits.exp - LDBL_MAX_EXP + 1; 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (e < MANH_SIZE - 1) { 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (e < 0) { /* raise inexact if x != 0 */ 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (huge + x > 0.0) 631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.exp > 0 || 641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project (u.bits.manh | u.bits.manl) != 0) 651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.e = u.bits.sign ? -1.0 : 0.0; 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); 681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (((u.bits.manh & m) | u.bits.manl) == 0) 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (x); /* x is integral */ 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.sign) { 711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef LDBL_IMPLICIT_NBIT 721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (e == 0) 731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.exp++; 741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else 751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project INC_MANH(u, 1llu << (MANH_SIZE - e - 1)); 771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (huge + x > 0.0) { /* raise inexact flag */ 791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manh &= ~m; 801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manl = 0; 811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else if (e < LDBL_MANT_DIG - 1) { 841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); 851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ((u.bits.manl & m) == 0) 861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (x); /* x is integral */ 871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.sign) { 881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (e == MANH_SIZE - 1) 891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project INC_MANH(u, 1); 901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else { 911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint64_t o = u.bits.manl; 921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1); 931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (u.bits.manl < o) /* got a carry */ 941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project INC_MANH(u, 1); 951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (huge + x > 0.0) /* raise inexact flag */ 981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u.bits.manl &= ~m; 991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (u.e); 1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 102