|
10 | 10 | #ifndef CPROVER_JAVA_BYTECODE_EXPR2JAVA_H
|
11 | 11 | #define CPROVER_JAVA_BYTECODE_EXPR2JAVA_H
|
12 | 12 |
|
| 13 | +#include <cmath> |
| 14 | +#include <numeric> |
| 15 | +#include <sstream> |
13 | 16 | #include <string>
|
14 | 17 | #include <ansi-c/expr2c_class.h>
|
15 | 18 |
|
@@ -50,4 +53,53 @@ class expr2javat:public expr2ct
|
50 | 53 | std::string expr2java(const exprt &expr, const namespacet &ns);
|
51 | 54 | std::string type2java(const typet &type, const namespacet &ns);
|
52 | 55 |
|
| 56 | +/// Convert floating point number to a string without printing |
| 57 | +/// unnecessary zeros. Prints decimal if precision is not lost. |
| 58 | +/// Prints hexadecimal otherwise, and/or java-friendly NaN and Infinity |
| 59 | +template <typename float_type> |
| 60 | +std::string floating_point_to_java_string(float_type value) |
| 61 | +{ |
| 62 | + const auto is_float = std::is_same<float_type, float>::value; |
| 63 | + static const std::string class_name = is_float ? "Float" : "Double"; |
| 64 | + if(std::isnan(value)) |
| 65 | + return class_name + ".NaN"; |
| 66 | + if(std::isinf(value) && value >= 0.) |
| 67 | + return class_name + ".POSITIVE_INFINITY"; |
| 68 | + if(std::isinf(value) && value <= 0.) |
| 69 | + return class_name + ".NEGATIVE_INFINITY"; |
| 70 | + const std::string decimal = [&]() -> std::string { // NOLINT |
| 71 | + // Using ostringstream instead of to_string to get string without |
| 72 | + // trailing zeros |
| 73 | + std::ostringstream raw_stream; |
| 74 | + raw_stream << value; |
| 75 | + const auto raw_decimal = raw_stream.str(); |
| 76 | + if(raw_decimal.find('.') == std::string::npos) |
| 77 | + return raw_decimal + ".0"; |
| 78 | + return raw_decimal; |
| 79 | + }(); |
| 80 | + const bool is_lossless = [&] { // NOLINT |
| 81 | + if(value == std::numeric_limits<float_type>::min()) |
| 82 | + return true; |
| 83 | + try |
| 84 | + { |
| 85 | + return std::stod(decimal) == value; |
| 86 | + } |
| 87 | + catch(std::out_of_range) |
| 88 | + { |
| 89 | + return false; |
| 90 | + } |
| 91 | + }(); |
| 92 | + const std::string lossless = [&]() -> std::string { // NOLINT |
| 93 | + if(is_lossless) |
| 94 | + return decimal; |
| 95 | + std::ostringstream stream; |
| 96 | + stream << std::hexfloat << value; |
| 97 | + return stream.str(); |
| 98 | + }(); |
| 99 | + const auto literal = is_float ? lossless + 'f' : lossless; |
| 100 | + if(is_lossless) |
| 101 | + return literal; |
| 102 | + return literal + " /* " + decimal + " */"; |
| 103 | +} |
| 104 | + |
53 | 105 | #endif // CPROVER_JAVA_BYTECODE_EXPR2JAVA_H
|
0 commit comments