这是我的解决方案。为方便起见,我使用<string>
,但没有其他库。to_string(float x)
/函数以全精度格式将to_string(double x)
数字作为字符串返回。-1.23456789E-12
to_string(float x, const uint decimals)
/函数将to_string(double x, const uint decimals)
数字作为具有指定小数位数的字符串返回:-12345.68
例如,带有 2 个小数。这会降低精度,但更方便控制台输出。这里的数字限制在1.844E19
.
两种方法都正确处理了舍入。
#define to_string to_string_old // use own to_string methods
#include <string>
#undef to_string // use own to_string methods
using namespace std;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef int64_t slong;
typedef uint64_t ulong;
#define max_ulong 18446744073709551615ull
float pow(const float x, const uint n) {
float r = 1.0f;
for(uint i=0; i<n; i++) {
r *= x;
}
return r;
}
double pow(const double x, const uint n) {
double r = 1.0;
for(uint i=0; i<n; i++) {
r *= x;
}
return r;
}
void split_float(float x, uint& integral, uint& decimal, int& exponent) {
if(x>=10.0f) { // convert to base 10
if(x>=1E32f) { x *= 1E-32f; exponent += 32; }
if(x>=1E16f) { x *= 1E-16f; exponent += 16; }
if(x>= 1E8f) { x *= 1E-8f; exponent += 8; }
if(x>= 1E4f) { x *= 1E-4f; exponent += 4; }
if(x>= 1E2f) { x *= 1E-2f; exponent += 2; }
if(x>= 1E1f) { x *= 1E-1f; exponent += 1; }
}
if(x>0.0f && x<=1.0f) {
if(x<1E-31f) { x *= 1E32f; exponent -= 32; }
if(x<1E-15f) { x *= 1E16f; exponent -= 16; }
if(x< 1E-7f) { x *= 1E8f; exponent -= 8; }
if(x< 1E-3f) { x *= 1E4f; exponent -= 4; }
if(x< 1E-1f) { x *= 1E2f; exponent -= 2; }
if(x< 1E0f) { x *= 1E1f; exponent -= 1; }
}
integral = (uint)x;
float remainder = (x-integral)*1E8f; // 8 decimal digits
decimal = (uint)remainder;
if(remainder-(float)decimal>=0.5f) { // correct rounding of last decimal digit
decimal++;
if(decimal>=100000000u) { // decimal overflow
decimal = 0;
integral++;
if(integral>=10u) { // decimal overflow causes integral overflow
integral = 1;
exponent++;
}
}
}
}
void split_double(double x, uint& integral, ulong& decimal, int& exponent) {
if(x>=10.0) { // convert to base 10
if(x>=1E256) { x *= 1E-256; exponent += 256; }
if(x>=1E128) { x *= 1E-128; exponent += 128; }
if(x>= 1E64) { x *= 1E-64; exponent += 64; }
if(x>= 1E32) { x *= 1E-32; exponent += 32; }
if(x>= 1E16) { x *= 1E-16; exponent += 16; }
if(x>= 1E8) { x *= 1E-8; exponent += 8; }
if(x>= 1E4) { x *= 1E-4; exponent += 4; }
if(x>= 1E2) { x *= 1E-2; exponent += 2; }
if(x>= 1E1) { x *= 1E-1; exponent += 1; }
}
if(x>0.0 && x<=1.0) {
if(x<1E-255) { x *= 1E256; exponent -= 256; }
if(x<1E-127) { x *= 1E128; exponent -= 128; }
if(x< 1E-63) { x *= 1E64; exponent -= 64; }
if(x< 1E-31) { x *= 1E32; exponent -= 32; }
if(x< 1E-15) { x *= 1E16; exponent -= 16; }
if(x< 1E-7) { x *= 1E8; exponent -= 8; }
if(x< 1E-3) { x *= 1E4; exponent -= 4; }
if(x< 1E-1) { x *= 1E2; exponent -= 2; }
if(x< 1E0) { x *= 1E1; exponent -= 1; }
}
integral = (uint)x;
double remainder = (x-integral)*1E16; // 16 decimal digits
decimal = (ulong)remainder;
if(remainder-(double)decimal>=0.5) { // correct rounding of last decimal digit
decimal++;
if(decimal>=10000000000000000ull) { // decimal overflow
decimal = 0;
integral++;
if(integral>=10u) { // decimal overflow causes integral overflow
integral = 1;
exponent++;
}
}
}
}
string decimal_to_string_float(uint x, int digits) {
string r = "";
while((digits--)>0) {
r = (char)(x%10+48)+r;
x /= 10;
}
return r;
}
string decimal_to_string_double(ulong x, int digits) {
string r = "";
while((digits--)>0) {
r = (char)(x%10+48)+r;
x /= 10;
}
return r;
}
string to_string(const string& s){
return s;
}
string to_string(const char& c) {
return string(1, c);
}
string to_string(ulong x) {
string r = "";
do {
r = (char)(x%10+48)+r;
x /= 10;
} while(x);
return r;
}
string to_string(slong x) {
return x>=0 ? to_string((ulong)x) : "-"+to_string((ulong)(-x));
}
string to_string(uint x) {
string r = "";
do {
r = (char)(x%10+48)+r;
x /= 10;
} while(x);
return r;
}
string to_string(int x) {
return x>=0 ? to_string((uint)x) : "-"+to_string((uint)(-x));
}
string to_string(float x) { // convert float to string with full precision (<string> to_string() prints only 6 decimals)
string s = "";
if(x<0.0f) { s += "-"; x = -x; }
if(isnan(x)) return s+"NaN";
if(isinf(x)) return s+"Inf";
uint integral, decimal;
int exponent = 0;
split_float(x, integral, decimal, exponent);
return s+to_string(integral)+"."+decimal_to_string_float(decimal, 8)+(exponent!=0?"E"+to_string(exponent):"");
}
string to_string(double x) { // convert double to string with full precision (<string> to_string() prints only 6 decimals)
string s = "";
if(x<0.0) { s += "-"; x = -x; }
if(isnan(x)) return s+"NaN";
if(isinf(x)) return s+"Inf";
uint integral;
ulong decimal;
int exponent = 0;
split_double(x, integral, decimal, exponent);
return s+to_string(integral)+"."+decimal_to_string_double(decimal, 16)+(exponent!=0?"E"+to_string(exponent):"");
}
string to_string(float x, const uint decimals) { // convert float to string with specified number of decimals
string s = "";
if(x<0.0f) { s += "-"; x = -x; }
if(isnan(x)) return s+"NaN";
if(isinf(x)||x>(float)max_ulong) return s+"Inf";
const float power = pow(10.0f, min(decimals, 8u));
x += 0.5f/power; // rounding
const ulong integral = (ulong)x;
const uint decimal = (uint)((x-(float)integral)*power);
return s+to_string(integral)+(decimals==0 ? "" : "."+decimal_to_string_float(decimal, min((int)decimals, 8)));
}
string to_string(double x, const uint decimals) { // convert float to string with specified number of decimals
string s = "";
if(x<0.0) { s += "-"; x = -x; }
if(isnan(x)) return s+"NaN";
if(isinf(x)||x>(double)max_ulong) return s+"Inf";
const double power = pow(10.0, min(decimals, 16u));
x += 0.5/power; // rounding
const ulong integral = (ulong)x;
const ulong decimal = (ulong)((x-(double)integral)*power);
return s+to_string(integral)+(decimals==0 ? "" : "."+decimal_to_string_double(decimal, min((int)decimals, 16)));
}