Знаете ли вы, как сделать эту простую строку кода без ошибок, используя Boost :: multiprecison?
boost::multiprecision::cpp_int v, uMax, candidate;
//...
v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
При использовании MSVC для «sqrt» есть ошибка, которую можно исправить с помощью:
v += 6 * ceil((sqrt(static_cast<boost::multiprecision::cpp_int>(uMax * uMax - candidate)) - v) / 6);
Тогда есть ошибка для «ceil», и это можно исправить с помощью:
namespace bmp = boost::multiprecision;
typedef bmp::number<bmp::cpp_dec_float<0>> float_bmp;
v += 6 * ceil(static_cast<float_bmp>((sqrt(static_cast<bmp::cpp_int>(uMax * uMax - candidate)) - v) / 6));
Тогда возникает ошибка «общего взаимопревращения»!?!
Я думаю, что должен быть более элегантный способ реализовать такую простую строку кода, не так ли?
Дайте мне знать, если у вас есть идеи по этому поводу, пожалуйста.
С уважением.
«Проблема» (это на самом деле особенность) вы используете number<>
интерфейс с включенными шаблонными выражениями.
Это означает, что многие операции могут быть значительно оптимизированы или даже исключены до того, как компилятор сгенерирует код.
У вас есть два варианта:
сломать вещи
using BF = boost::multiprecision::cpp_bin_float_100;
using BI = boost::multiprecision::cpp_int;
BI v = 1, uMax = 9, candidate = 1;
//v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
BF tmp1(uMax * uMax - candidate);
BF tmp2(sqrt(tmp1) - BF(v));
BF tmp3(ceil(tmp2 / 6));
BI tmp4(tmp3.convert_to<BI>());
std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << "\n";
v = v + 6*tmp4;
Чтобы ты мог написать
v += 6*ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
Что работает путем принудительного вычисления шаблонов выражений (и, возможно, преобразования с потерями из float -> integer с использованием convert_to<>
).
В общем, вы можете переключиться на версии без выражений-шаблонов типов:
using BF = mp::number<mp::cpp_bin_float_100::backend_type, mp::et_off>;
using BI = mp::number<mp::cpp_int::backend_type, mp::et_off>;
В этом конкретном случае это не сильно изменится, потому что вам все равно придется делать «принуждения» типа от integer -> float -> integer:
v += 6 * ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
Упрощая, если вы вместо этого сделаете все типы плавающими (например, cpp_dec_float), вы можете избавиться от этих усложняющих артефактов:
using BF = mp::number<mp::cpp_dec_float_100::backend_type, mp::et_off>;
BF v = 1, uMax = 9, candidate = 1;
v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
ПРЕДОСТЕРЕЖЕНИЕ Используйте свой профилировщик, чтобы увидеть, что с помощью
et_off
не вызывает проблем с производительностью в вашей базе кода
Вот демонстрационная программа, показывающая все три подхода:
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/number.hpp>
int main() {
namespace mp = boost::multiprecision;
//v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
{
using BF = mp::cpp_bin_float_100;
using BI = mp::cpp_int;
BI v = 1, uMax = 9, candidate = 1;
#ifdef DEBUG
BF tmp1(uMax * uMax - candidate);
BF tmp2(sqrt(BF(uMax * uMax - candidate)) - BF(v));
BF tmp3(ceil(tmp2 / 6));
BI tmp4(tmp3.convert_to<BI>());
std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << "\n";
#endif
v += 6*ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
}
{
using BF = mp::number<mp::cpp_bin_float_100::backend_type, mp::et_off>;
using BI = mp::number<mp::cpp_int::backend_type, mp::et_off>;
BI v = 1, uMax = 9, candidate = 1;
v += 6 * ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
}
{
using BF = mp::number<mp::cpp_dec_float_100::backend_type, mp::et_off>;
BF v = 1, uMax = 9, candidate = 1;
v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
}
}
использование boost::multiprecision::sqrt
а также boost::multiprecision::ceil
,