简体   繁体   English

为什么从浮点到 integer 的转换会截断?

[英]Why does a cast from floating point to integer truncate?

In C and C++, we all know that converting a floating point value into an integer performs a truncation .在 C 和 C++ 中,我们都知道将浮点值转换为 integer 会执行截断 That means, a fix towards zero , both for static_cast and for C style casts.这意味着,对于static_cast和 C 风格的演员表,对零的修复。

static_assert(static_cast<int>(2.9) == 2);
static_assert((int)-3.7 == -3);

To convert a floating point number into an integer, there are 4 options, each of them is implemented by a standard function from <cmath> :要将浮点数转换为 integer,有 4 个选项,每个选项都由<cmath>中的标准 function 实现:

  1. round
  2. floor
  3. ceil
  4. trunc

I ordered the options from the most often used to the least often used, from my own experience (it is somewhat subjective).根据我自己的经验,我从最常用到最不常用的选项排序(这有点主观)。

Truncation toward zero means that all values from -0.999... to 0.999... are converted to 0. There is a for that reason a mathematical anomaly near 0, which makes truncation rarely useful.向零截断意味着从 -0.999... 到 0.999... 的所有值都转换为 0。因此,在 0 附近存在数学异常,这使得截断很少有用。 My impression is that nearly every time a programmer directly casts a floating point to an integer, he actually wants floor , but can afford trunc behavior because the value is supposed to be always positive.我的印象是,几乎每次程序员直接将浮点数转换为 integer 时,他实际上都想要floor ,但可以承受trunc行为,因为该值应该始终为正。

My question is: what were the motivations to select the 4th option, truncate?我的问题是:select 第四个选项截断的动机是什么? I bet this is mostly historical, but when C was originally developed, there must have been some good reason to select truncation over the more useful rounding or flooring.我敢打赌这主要是历史性的,但是当最初开发 C 时,肯定有一些充分的理由将 select 截断而不是更有用的舍入或地板。

You use it when you want to floor the modulus of the value irrespective of the sign.当您想要对值的模数进行下限时使用它,而与符号无关。 This can happen for multiple reasons that are particular to every application.发生这种情况的原因有多种,每个应用程序都是特定的。 You might have it in Physics, Finance, Engineering, etc.你可能会在物理、金融、工程等领域拥有它。

On x86_64, trunc(float) is mapped to the roundss instruction on glibc在 x86_64 上, trunc(float)映射到glibc 上的roundss指令

ENTRY(__truncf_sse41)
        roundss        $11, %xmm0, %xmm0
        ret
END(__truncf_sse41)

The constant $11 above, it's an immediate operand to the actual instruction and determines the rounding characteristics.上面的常量 $11,它是实际指令的立即操作数,并确定舍入特性。 That particular instruction contain the choices you mentioned (see Intel Intrinsics Guide ):该特定指令包含您提到的选项(请参阅Intel Intrinsics Guide ):

__m128 _mm_round_ss (__m128 a, __m128 b, int rounding)
Synopsis
__m128 _mm_round_ss (__m128 a, __m128 b, int rounding)
#include <smmintrin.h>
Instruction: roundss xmm, xmm, imm8
CPUID Flags: SSE4.1
Description
Round the lower single-precision (32-bit) floating-point element in b using the rounding parameter, store the result as a single-precision floating-point element in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.
Rounding is done according to the rounding[3:0] parameter, which can be one of:
    (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions
    (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC)     // round down, and suppress exceptions
    (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC)     // round up, and suppress exceptions
    (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC)        // truncate, and suppress exceptions
    _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE

So this is by no means a language choice, it's a demand from users.所以这绝不是语言的选择,而是用户的需求。

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

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