diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 8645f97cc8d2..ce43a16e4225 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -7,20 +7,30 @@ permissions: jobs: build: - runs-on: macos-11 strategy: matrix: + os: [macos-11, macos-13] build_type: [Debug, Release] - std: [11, 17] + std: [11, 17, 20] + exclude: + - { os: macos-11, std: 20 } + - { os: macos-13, std: 11 } + - { os: macos-13, std: 17 } include: - shared: -DBUILD_SHARED_LIBS=ON + runs-on: '${{ matrix.os }}' + steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Set timezone run: sudo systemsetup -settimezone 'Asia/Yekaterinburg' + - name: Select Xcode 14.3 (macOS 13) + run: sudo xcode-select -s "/Applications/Xcode_14.3.app" + if: ${{ matrix.os == 'macos-13' }} + - name: Create Build Environment run: cmake -E make_directory ${{runner.workspace}}/build diff --git a/include/fmt/format.h b/include/fmt/format.h index a1a4199316cb..d4951cb58d5a 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3317,6 +3317,23 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, format_hexfloat(static_cast(value), precision, specs, buf); } +template FMT_CONSTEXPR auto iceil(Float value) -> int { + auto min = (std::numeric_limits::min)(); + auto max = (std::numeric_limits::max)(); + ignore_unused(min, max); + FMT_ASSERT(value >= min && value <= max, "value not in int range"); + do { + auto mid = min + static_cast((static_cast(max) - + static_cast(min)) / + 2); + if (mid < value) + min = mid; + else + max = mid; + } while (min + 1 != max); + return max; +} + template FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, buffer& buf) -> int { @@ -3347,8 +3364,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). // This is based on log10(value) == log2(value) / log2(10) and approximation // of log2(value) by e + num_fraction_bits idea from double-conversion. - exp = static_cast( - std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); + exp = iceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10); dragon_flags = dragon::fixup; } else if (precision < 0) { // Use Dragonbox for the shortest format. diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 35e9d568acc6..cdd3416401f0 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -523,3 +523,18 @@ TEST(format_impl_test, to_utf8) { EXPECT_EQ(s, u.str()); EXPECT_EQ(s.size(), u.size()); } + +TEST(format_impl_test, iceil) { + for (double v : std::initializer_list{ + ((std::numeric_limits::min)() + 0.5), + -1.2, + -0.2, + 0.0, + 0.2, + 1.2, + 4.0, + ((std::numeric_limits::max)() - 0.5), + }) { + EXPECT_EQ(fmt::detail::iceil(v), static_cast(std::ceil(v))); + } +}