我在基于UNIX的系统上遇到问题sprintf没有正确地舍入值.
例如
double tmp = 88888888888885.875
char out[512];
Run Code Online (Sandbox Code Playgroud)
这是88,888,888,888,885.875只是为了让眼睛更容易.我给出了这样一个特别而又大的例子,因为它似乎在较小的数字上工作正常.
我试图以下面的方式使用它
sprintf(out, "%021.2f", tmp);
printf("out = %s\n", tmp);
Run Code Online (Sandbox Code Playgroud)
在Windows上,这会导致:
out = 000088888888888885.88
Run Code Online (Sandbox Code Playgroud)
例如AIX,但在Linux中也显示:
out = 000088888888888885.87
Run Code Online (Sandbox Code Playgroud)
为什么会这样?任何想法以及如何使它在Win/Unix上的行为方式相同
谢谢
我在我的linux服务器上使用PHP 5.2.13.在舍入数字时,我遇到了奇怪的错误.这是我的测试用例:
<?php
echo " " . round(1.505, 2) . "\n";
echo " " . round(11.505, 2) . "\n";
echo " " . round(111.505, 2) . "\n";
echo " " . round(1111.505, 2) . "\n";
echo " " . round(11111.505, 2) . "\n";
echo " " . round(111111.505, 2) . "\n";
echo " " . round(1111111.505, 2) . "\n";
echo " " . round(11111111.505, 2) . "\n";
echo "" . round(111111111.505, 2) . "\n";
Run Code Online (Sandbox Code Playgroud)
这是结果:
1.51
11.51
111.51
1111.51
11111.51 …Run Code Online (Sandbox Code Playgroud) 我正在将程序从Scilab代码转换为C++.特别是一个循环产生的结果与原始的Scilab代码略有不同(这是一段很长的代码,因此我不会在问题中包含它,但我会尽力总结下面的问题).
问题是,循环的每一步都使用上一步的计算.此外,计算之间的差异仅在第100,000次迭代(大约300,000次)中变得明显.
注意:我正在使用"format(25)"将我的C++程序的输出与Scilab 5.5.2的输出进行比较.命令.含义我正在比较25位有效数字.我还想指出,我理解在一定数量的位之后无法保证精度,但在评论之前阅读下面的部分.到目前为止,两种语言之间的所有计算都相同,最多可达25位.
为了找到问题的根源,到目前为止我已经尝试过:
我已经设法确认Scilab正在使用IEEE 754双打(根据语言文档).另外,根据维基百科,C++ 并不需要使用IEEE 754双打,但我可以告诉,我到处使用双C++中它已完全匹配的Scilab的结果.
我还读过每个计算机科学家应该知道的关于浮点运算的内容,IEEE不要求超越函数完全舍入.考虑到这一点,我在两种语言中比较了这些函数的结果(sin(),cos(),exp()),结果看起来是相同的(最多25位).
我重复了上述步骤,以便使用sqrt()和pow().以及Pi的值(我在C++中使用M_PI,在Scilab中使用%pi).同样,结果是一样的.
注意:有趣的是,我注意到,对于上述所有计算,两种语言之间的结果与计算的实际结果(浮点运算之外)相匹配得更远.例如:
使用Wolfram Alpha = sin(x)的值= 0.123456789 .....
使用Scilab&C++ = sin(x)的值= 0.12345yyyyy .....
甚至一旦使用Scilab或C++计算的值开始与实际结果不同(来自Wolfram).每种语言的结果仍然相互匹配.这使我相信大多数值都以相同的方式计算(在两种语言之间).即使IEEE 754不要求它们.
我最初的想法是上述前三点之一,两种语言之间的实现方式不同.但据我所知,一切似乎都会产生相同的结果.
是否有可能即使这些循环的所有输入都相同,结果也可能不同?可能是因为一个非常小的错误(过去我能看到的25位数)正在发生,随着时间累积?如果是这样,我该如何解决这个问题呢?
我试图通过取一个整数乘积除以另一个整数乘积的比率来形成双精度浮点数(64位).我希望以减少舍入误差的方式这样做.
我熟悉Kahan加法和减法求和.什么技术适合分裂?
分子是许多长值(数万)的乘积,同样是分母.我也希望防止溢出和下溢.(一个应用程序通过在足够数量的术语后停止来估计无限产品.)
我尝试过的一件事是将易于计算的数字考虑在内(使用已知质数的试验除法高达一百万)并取消常见因素,这有助于,但还不够.我的错误大约是1.0E-13.
我在C#中工作,但欢迎任何使用IEEE标准浮点数的代码.
研究:
我遇到了一篇很好的论文,讨论了+ - x /,Horner规则(多项式)和平方根的EFT(无误差变换).标题是Philippe Langlois的"浮点4算术中的4个准确4算法".见http://www.mathematik.hu-berlin.de/~gaggle/S09/AUTODIFF/projects/papers/langlois_4ccurate_4lgorithms_in_floating_point_4rithmetic.pdf
上面我指的是卡普和马克斯坦(分裂):https://cr.yp.to/bib/1997/karp.pdf
我刚刚遇到了Kahan(或补偿)求和算法,用于最小化舍入,我想知道是否有等效的除法和/或乘法算法,以及减法(如果恰好有一个,我知道关于结社).任何语言,伪代码或链接的实现示例都会很棒!
谢谢
function KahanSum(input)
var sum = 0.0
var c = 0.0
for i = 1 to input.length do
y = input[i] - c // why subtraction?
t = sum + y
c = (t - sum) - y
sum = t
return sum
Run Code Online (Sandbox Code Playgroud)
是否有一个特定的原因,它使用减法(而不是添加)?如果我在计算中交换操作数c,我可以使用加法吗?不知怎的,这对我来说更有意义:
function KahanSum(input)
var sum = 0.0
var c = 0.0
for i = 1 to input.length do
y = input[i] + c // addition instead of subtraction
t = sum …Run Code Online (Sandbox Code Playgroud) 用PHP编写的带有MySQL数据库的Web应用程序.
我有一个系统,可以在分摊成本时为许多人计算不同的成本.例如,人员A购买的东西为10,而人员B,C和D应该分摊成本.
因此,该系统应该记录A人10 的正记录和B,C和D的10/3的负记录.
但是,当这样做时; 四舍五入后B,C和D均为-3.33.这当然并不加起来总数的10什么的要对这个问题的最好方法是什么?一个最优的解决方案是随机化一个人获得的稍微大一点的成本.
一个可能的解决方案是,如果我只是让最后一个人的债务10 - (A + B),但是如果四个人分摊成本例如13.34 则存在问题.那么不同的部分将是3.34,3.34,3.34和3.32,而最佳分割将是3.34,3.34,3.33,3.33.
有些人可能会争辩说,只要有足够的小数,这只是在拥有大量行时的问题.但在一个经济的系统中,我认为从一开始就拥有一个故障安全系统是很重要的.它需要是可扩展的,甚至不会有任何误差.不公平是好的,只是没有错误.
类似的问题:总和分值问题(处理舍入误差)
我正在开发一个应用程序,它将-1.0到1.0范围内的Float样本转换为带符号的16位,以确保优化(SSE)例程的输出是准确的我已编写了一组运行非优化版本的测试SSE版本并比较它们的输出.
在开始之前,我已经确认SSE舍入模式设置为最接近.
在我的测试用例中,公式为:
ratio = 65536 / 2
output = round(input * ratio)
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,结果是准确的,但在一个特定的输入上,我看到输入失败-0.8499908447265625.
-0.8499908447265625 * (65536 / 2) = -27852.5
Run Code Online (Sandbox Code Playgroud)
正常代码正确地将其舍入为-27853,但SSE代码将此舍入为-27852.
这是使用中的SSE代码:
void Float_S16(const float *in, int16_t *out, const unsigned int samples)
{
static float ratio = 65536.0f / 2.0f;
static __m128 mul = _mm_set_ps1(ratio);
for(unsigned int i = 0; i < samples; i += 4, in += 4, out += 4)
{
__m128 xin;
__m128i con;
xin = _mm_load_ps(in);
xin = _mm_mul_ps(xin, …Run Code Online (Sandbox Code Playgroud) 我想在我的设备上摆脱一个像素问题.我正在设计一个如下所示的日历
我正在为此目的使用UICollectionViewCell
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat collectionViewWidth = (CGRectGetWidth(collectionView.frame) / 7);
CGFloat collectionViewHeight = 48;
return CGSizeMake(collectionViewWidth, collectionViewHeight);
}
Run Code Online (Sandbox Code Playgroud)
问题是,如果我增加宽度甚至0.0000001点,那么每行绘制的单元格数量是6而不是7.我已尝试增加UIEdgeInset(0.00001),但这是同样的问题.流布局的属性已正确设置.
layout.minimumInteritemSpacing = 0.0f;
layout.minimumLineSpacing = 0.0f;
Run Code Online (Sandbox Code Playgroud)
如何在不留空隙的情况下使单元尺寸保持一致?电池的实际宽度为53.571428571428569(375/7).如果我将值四舍五入到53.58,那么我得到以下视图

我在Delphi 2010中有一个四舍五入的奇数,其中一些数字在取整中四舍五入,但在formatfloat中向上取整。
我完全知道十进制数字的二进制表示形式有时会产生误导性的结果,但是在那种情况下,我希望formatfloat和roundto会给出相同的结果。
我也看到建议,这是应该使用“ Currency”的东西,但是正如您在下面看到的,Currency和Double给出的结果相同。
program testrounding;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,Math;
var d:Double;
c:Currency;
begin
d:=534.50;
c:=534.50;
writeln('Format: ' +formatfloat('0',d));
writeln('Roundto: '+formatfloat('0',roundto(d,0)));
writeln('C Format: ' +formatfloat('0',c));
writeln('C Roundto: '+formatfloat('0',roundto(c,0)));
readln;
end.
Run Code Online (Sandbox Code Playgroud)
结果如下:
Format: 535
Roundto: 534
C Format: 535
C Roundto: 534
Run Code Online (Sandbox Code Playgroud)
我已经看过为什么RoundTo(87.285,-2)=> 87.28的结果,建议的补救措施似乎并不适用。