繁体   English   中英

如何获得浮点除法的正确下限?

[英]How to get the correct floor of a floating-point division?

我想获得两个正浮点数相除的浮点下限。 特别是我追求的最大浮点数不大于除法下限的确切值。 股息可以很大,除数可以很小,但在我的应用程序中,除法中没有溢出或下溢的风险。

如果我这样做:

quotient = floor(dividend / divisor);

我的问题是,当商大于尾数的精度时,除法的结果始终是 integer,因此 FPU 将它舍入而不是铺平它,因为它处于舍入到最近或偶数模式; floor()也什么都不做,因为它已经输入了 integer。 由于它是四舍五入的,有时结果会大于确切的地板,这不是我所追求的。

在除法期间更改 FPU 的舍入模式将是一个解决方案,但这不是一个选项,所以除此之外,我怎样才能获得正确的地板?

(相关: 如何正确设置浮点对总和

我最终使用整数进行除法。 以下函数仅适用于 IEC-559 浮点数或双精度数:

#include <stdint.h>
#include <math.h>

#ifdef __GNUC__
#define int_fast128 __int128
// other compilers pending
#endif

double truncdiv(double a, double b)
{
  int ae, be, re, sh, sh2;
  int_fast64_t am, bm;
  int_fast64_t rm;
  am = 9007199254740992. * frexp(a, &ae);
  bm = 9007199254740992. * frexp(b, &be);
  sh = 52 + (am < bm);  // add 1 if quotient is 1 bit short
  re = ae - be - sh;
  // Truncate the mantissa when the exponent is in range -52..0
  sh2 = re >= 0 ? 0 : -re;
  rm = re < -52 ? 0 : (((int_fast128)am << sh) / bm) >> sh2 << sh2;
  return ldexp(rm, re);
}

请注意,此 function 不是为处理有符号零、NaN、无穷大、非正规、溢出或被零除而编写的。 它也是截断除法而不是下除法,即它向零舍入,而不是向负无穷大。 它需要 128 位 integer 类型,可能并非在所有平台上都可用。 对于单精度,它只需要一个 64 位 integer 类型,它得到更广泛的支持:

#include <stdint.h>
#include <math.h>

float truncdivf(float a, float b)
{
  int ae, be, re, sh, sh2;
  int_fast32_t am, bm;
  int_fast32_t rm;
  am = 16777216.f * frexpf(a, &ae);
  bm = 16777216.f * frexpf(b, &be);
  sh = 23 + (am < bm);  // add 1 if quotient is 1 bit short
  re = ae - be - sh;
  // Truncate the mantissa when the exponent is in range -23..0
  sh2 = re >= 0 ? 0 : -re;
  rm = re < -23 ? 0 : (((int_fast64_t)am << sh) / bm) >> sh2 << sh2;
  return ldexpf(rm, re);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM