这是我想知道自己15岁时的谜,但我失败了。我仍然不知道答案。
这是一个幼稚且有缺陷的解决方案(就像我在Stack Overflow上看到的其他失败尝试一样):
Job for mysql.service failed because the control process exited with error code.
See "systemctl status mysql.service" and "journalctl -xe" for details.
此处的语言为Javascript,但问题是与语言无关。但是,请尽可能对现有代码进行改进。
如果此方法的工作方式取决于语言,那么我将对一些见解在各种编程语言(例如Javascript)中的外观有所了解。
答案 0 :(得分:0)
(我没有足够的声誉来发表评论,所以诉诸于使用答案...)
我注意到您将精度超出了300个数字,远远超出了浮点数的精度,因此结果不准确。如果您正在寻找一种可以进行高精度计算的方法,则可以使用BigInt,并相应地扩展数字。例如,可以通过以下功能处理计算1000/17。 (请注意,这只是一个用于处理两个整数之间的高精度除法的概念函数,但可以通过按比例放大 dividend 和 divisor 直到它们成为非整数的基础)是整数,并相应地调整数字。此外,您可能需要增加一些额外的“隐藏”精度来处理舍入)...
function divideN(dividend, divisor, digits) {
dividend = dividend * 10n ** (BigInt(digits) * 2n);
divisor = divisor * 10n ** BigInt(digits);
var s = (dividend/divisor).toString();
if (s.length < digits) {
s = "0".repeat(digits - s.length) + s;
}
s = s.slice(0, s.length - digits) + "." + s.slice(-digits);
return s;
}
BigInt要求数字以“ n”结尾,因此需要按以下方式调用该函数...
divideN(1000n,17n,100)
...在这种情况下返回...
"58.8235294117647058823529411764705882352941176470588235294117647058823529411764705882352941176470588235"
请注意,在这种情况下,由于除数(1000)对除数(17)的相对大小,返回的精度是102位而不是100位。
答案 1 :(得分:0)
我不是 JAVASCRIPT 编码器,所以我坚持使用 C ++ ...
将数字转换为十进制数的字符串比使用二进制数或幂的基数(bin,oct,hex)要复杂得多,这是因为通常计算机上的所有数字都以二进制数存储,而不是十年的如果转换整数或小数部分,则也不相同。假设我们有数字x
,并且想要用ASCII编码字符串s
,因此这是基本转换的工作方式:
句柄sign
s="+";
if (x<0.0) { x=-x; s="-"; }
如您所见,它很简单。某些数字格式具有单独的符号位(通常是msb),因此在这种情况下,代码可以转换为位操作,例如32位float
:
DWORD* dw=(DWORD*)(&x); // allow bit manipulation
s="+";
s[0]+=(((*dw)>>30)&2); // ASCII +,- codes are 2 apart
(*dw)&=0x7FFFFFFF; // x=abs(x)
因此我们为字符串提取了符号字符,并使x
无符号。
处理x
的整数部分
整数除以打印基数,将
整数转换为字符串,这样:
y=floor(x); // integer part
if (y)
for (;y;) // until number is nonzero
{
s+='0'+(y%10); // works only for up to 10 base
y/=10;
}
else s+='0'; // handle y=0 separately
因此,每个除法的其余部分都是字符串的期望数字,但顺序相反。因此,在转换后,可以通过单个for循环将字符串中的数字反转,也可以直接按相反的顺序存储数字。但是对于tat,您需要知道数字整数部分的位数。这是通过
digits = ceil(log(y)/log(base)) + 1
所以十进制:
digits = ceil(log10(y)) + 1
处理x
的小数部分
通过乘以乘以转换基础进行转换。
z=x-floor(x); // fractional part
if (z)
for (s+='.';z;) // until number is nonzero here you can limit to number of digits
{
z*=10.0;
s+='0'+int(floor(z)); // works only for up to 10 base
z-=floor(z);
}
这将按顺序返回数字,所以这次不会反转...
我直接在SO编辑器中对所有代码进行了编码,因此可能存在隐藏的语法错误。
现在通常的打印功能还具有格式化功能,该格式可以添加零或空格填充或截取高于某个值的小数位数,等等...
如果您有一个x
,那么这会慢很多,因为您不能再像+,-,*,/
那样处理基本的O(1)
操作,并且通常更快地创建hex
字符串,然后使用8位算术将字符串转换为十进制,或使用bignum所存储的已用DATA WORD中的最大10的幂。 hex -> dec
转换可以像这样完成:
但是对于非常大的字符串,它将再次变慢。在这种情况下,可以使用类似于Schönhage-Strassen乘法的 FFT / NTT 方法来加快速度,但是我以前从未尝试过将其用于打印,因此我对这种方法。
还请注意,确定数值的位数对于数字的小数部分而言并不规则(请参见上面的链接),因此您需要注意的是,可以用1-2
位数字来代替。
[Edit1]舍入字符串
简单地讲,如果在小数部分(任何非零数字之后)中检测到n
所导致的零或9,则需要停止打印并舍入。零只是被切掉的,而九也需要切掉,其余的要在字符串中增加一个。这样的操作可能溢出到字符串中没有的1位数字,因此在这种情况下,只需插入1
。
当我将所有内容放在一起时,会想到以下 C ++ / VCL 代码(基于 VCL AnsiString
数据类型):
AnsiString print(double x)
{
char c;
int i,j;
double y,a;
AnsiString s;
const int B=10; // chose base 2...16
const double b=B; // base
const double _b=1.0/b; // 1/base
const char digit[16]="0123456789ABCDEF";
#define _enable_rounding
#ifdef _enable_rounding
const int round_digits=5; // min consequent 0s or B-1s to triger rounding
int cnt0=0,cnt1=0; // consequent digit counters
int ena=0; // enabled consequent digit counters? after first nonzero digit
#endif
// here you should handle NaN and Inf cases
// handle sign
s="+";
if (x<0.0) { x=-x; s="-"; }
// integer part
y=floor(x);
if (y) for (;y>0.0;) // until number is nonzero
{
a=y; y=floor(y*_b); // the same as y/=10 on integers
a-=y*b; // the same as a=y%10 on integers
i=int(a);
s+=digit[i];
#ifdef _enable_rounding
ena|=i;
#endif
}
else s+='0'; // handle y=0 separately
// reverse string skipping +/- sign (beware AnsiString is indexed from 1 up to its length included!!!)
for (i=2,j=s.Length();i<j;i++,j--){ c=s[i]; s[i]=s[j]; s[j]=c; }
// fractional part
y=x-floor(x);
if (y) for (s+='.';y>0.0;) // until number is nonzero here you can limit to number of digits
{
y*=b;
a=floor(y);
y-=a;
i=int(a);
s+=digit[i];
#ifdef _enable_rounding
ena|=i;
// detect consequent rounding digits
if (ena)
{
if (i== 0){ cnt0++; cnt1=0; }
else if (i==B-1){ cnt1++; cnt0=0; }
else { cnt0=0; cnt1=0; }
}
// round down .???00000000 by cut of zeros
if (cnt0>=round_digits)
{
s=s.SubString(1,s.Length()-cnt0); // by cut of zeros
break;
}
// round up .???999999999 by increment and cut of zeros (only base 10) !!!
if (cnt1>=round_digits)
{
s=s.SubString(1,s.Length()-cnt1); // cut off nines
for (j=1,i=s.Length();(i>=2)&&(j);i--)
{
c=s[i];
if (c=='.') continue;
if (c=='9'){ s[i]='0'; continue; }
j=0; s[i]++;
}
if (j) s=s.Insert("1",i+1); // overflow -> insert "1" after sign
if (s[s.Length()]=='.') // cut off decimal point if no fractional part left
s=s.SubString(1,s.Length()-1);
break;
}
#endif
}
return s;
}
您可以选择基础B=<2,16>
。您可以通过使用/注释#define _enable_rounding
来禁用舍入。请注意,舍入例程仅适用于基数10
,因为对于不同的基数,增量例程将具有一些不同的代码/常量,并且太懒了以至于无法通用地进行处理(这将是更长和更难理解的代码)。 round_digits
常数是触发舍入的随后零个或九个的阈值。