调整浮动以满足条件:abs(float) <= 0.5?

Adjust floats to satisfy the condition: abs(float) <= 0.5?

我有一个任意大小的浮点向量。我想调整浮点数,使它们满足条件 abs(float) <= 0.5. 小数部分应该保留,尽管它可能与原始值不同,因此设置“x = 0.5”是不正确的。如果浮点数接近整数,则丢弃它(输入的浮点数不能是整数或在任意精度内接近于1)。

这是我写的,但是代码看起来有点分支。我想知道是否有办法让它更优雅/更高效,或者我可能错过了一些重要的东西。

输入:浮点数

输出: 调整浮动 x,使 fabs(x) <= 0.5

整数部分的例子

  1. -5.3 -> -0.3(取小数部分,如果 abs(fractional) <= 0.5)
  2. -5.8 -> 0.2(添加最接近的整数,向上舍入,相对于绝对值)。
  3. 5.3 -> 0.3
  4. 5.8 -> -0.2(减去,但向下舍入)
  5. -5.5 -> -0.5(此处保留符号)
  6. 5.5 -> 0.5(此处保留符号)

只有小数部分的例子

  1. 0.3 -> 0.3

  2. 0.8 -> -0.2(减去 1)

  3. -0.3 -> -0.3

  4. -0.8 -> 0.2(加 1)

极端情况

  1. 任意整数 -> 0
  2. 0.5 -> 0.5
  3. -0.5 -> -0.5
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

float scale(float x)
{
  const auto integerPart = std::abs(static_cast<std::int32_t>(x));
  const auto fractionalPart = std::fabs(x - static_cast<std::int32_t>(x));
  if (x < 0) {
    if (integerPart == 0) {
      if (fractionalPart > 0.5) {
       x += 1;
      }
    }
    else {
     x += integerPart + (fractionalPart > 0.5 ? 1 : 0);
    }
  }
  else {
    if (integerPart == 0) {
      if (fractionalPart > 0.5) {
        x -= 1;
      }
    } else {
      x -= integerPart + (fractionalPart > 0.5 ? 1 : 0);
    }
  }
  return x;
}

int main() {
  std::vector<float> floats(10000);

  static std::default_random_engine e;
  static std::uniform_real_distribution<float> distribution(-5, 5);

  std::generate(floats.begin(), 
                floats.end(), 
                [&]() { return distribution(e); });

  for (std::size_t i = 0; i < floats.size(); ++i) {
    floats[i] = scale(floats[i]);
  }

  std::cout << std::boolalpha 
            << std::all_of(floats.cbegin(),
                           floats.cend(),
                           [&](const float x){ return std::fabs(x) <= 0.5; }) << "\n";

}

这里注意保留符号,如果小数部分超过0.5,则结果值的符号取反。

谢谢。

可以使用floor函数来减少分支数量:

#include <iostream>
#include <cmath>

float scale(float x) {
    bool neg = std::signbit(x);
    x -= std::floor(x + 0.5);
    if (!neg && x == -0.5) {
         return 0.5;
    } else {
         return x;
    }
}

int main() {
    std::cout << "-1.23 " << scale(-1.23) << std::endl;
    std::cout << "-0.5 " << scale(-0.5) << std::endl;
    std::cout << "0.123 " << scale(0.123) << std::endl;
    std::cout << "0.5 " << scale(0.5) << std::endl;
    std::cout << "1.23 " << scale(1.23) << std::endl;
}

-1.23 -0.23
-0.5 -0.5
0.123 0.123
0.5 0.5
1.23 0.23

这只是 remainder 函数,除了结果恰好为 ±½ 时使用的符号,可以通过从输入中复制符号来调整:

double ModifiedRemainder(double x)
{
    double y = std::remainder(x, 1);
    return std::fabs(y) == .5 ? std::copysign(y, x) : y;
}