- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在 C# 中,我想将 double 舍入到较低的精度,以便我可以将它们存储在关联数组中不同大小的桶中。与通常的舍入不同,我想舍入到一些有效位。因此,大数字在绝对值上的变化比小数字大得多,但它们往往会按比例变化。因此,如果我想四舍五入到 10 个二进制数字,我会找到十个最高有效位,并将所有低位归零,可能会添加一个小数字以进行四舍五入。
我更喜欢将“中途”数字四舍五入。
如果是整数类型,可能的算法如下:
1. Find: zero-based index of the most significant binary digit set H.
2. Compute: B = H - P,
where P is the number of significant digits of precision to round
and B is the binary digit to start rounding, where B = 0 is the ones place,
B = 1 is the twos place, etc.
3. Add: x = x + 2^B
This will force a carry if necessary (we round halfway values up).
4. Zero out: x = x mod 2^(B+1).
This clears the B place and all lower digits.
问题是找到一种有效的方法来找到最高位集。如果我使用的是整数,可以通过一些很酷的技巧来找到 MSB。如果可以的话,我不想调用 Round(Log2(x)) 。此函数将被调用数百万次。
注意:我已经阅读了这个 SO 问题:
What is a good way to round double-precision values to a (somewhat) lower precision?
它适用于 C++。我正在使用 C#。
更新:
这是我正在使用的代码(根据回答者提供的内容修改):
/// <summary>
/// Round numbers to a specified number of significant binary digits.
///
/// For example, to 3 places, numbers from zero to seven are unchanged, because they only require 3 binary digits,
/// but larger numbers lose precision:
///
/// 8 1000 => 1000 8
/// 9 1001 => 1010 10
/// 10 1010 => 1010 10
/// 11 1011 => 1100 12
/// 12 1100 => 1100 12
/// 13 1101 => 1110 14
/// 14 1110 => 1110 14
/// 15 1111 =>10000 16
/// 16 10000 =>10000 16
///
/// This is different from rounding in that we are specifying the place where rounding occurs as the distance to the right
/// in binary digits from the highest bit set, not the distance to the left from the zero bit.
/// </summary>
/// <param name="d">Number to be rounded.</param>
/// <param name="digits">Number of binary digits of precision to preserve. </param>
public static double AdjustPrecision(this double d, int digits)
{
// TODO: Not sure if this will work for both normalized and denormalized doubles. Needs more research.
var shift = 53 - digits; // IEEE 754 doubles have 53 bits of significand, but one bit is "implied" and not stored.
ulong significandMask = (0xffffffffffffffffUL >> shift) << shift;
var local_d = d;
unsafe
{
// double -> fixed point (sorta)
ulong toLong = *(ulong*)(&local_d);
// mask off your least-sig bits
var modLong = toLong & significandMask;
// fixed point -> float (sorta)
local_d = *(double*)(&modLong);
}
return local_d;
}
更新 2:Dekker 的算法
多亏了另一位受访者,我从 Dekker 的算法中得出了这一点。它舍入到最接近的值,而不是像上面的代码那样截断,并且它只使用安全代码:
private static double[] PowersOfTwoPlusOne;
static NumericalAlgorithms()
{
PowersOfTwoPlusOne = new double[54];
for (var i = 0; i < PowersOfTwoPlusOne.Length; i++)
{
if (i == 0)
PowersOfTwoPlusOne[i] = 1; // Special case.
else
{
long two_to_i_plus_one = (1L << i) + 1L;
PowersOfTwoPlusOne[i] = (double)two_to_i_plus_one;
}
}
}
public static double AdjustPrecisionSafely(this double d, int digits)
{
double t = d * PowersOfTwoPlusOne[53 - digits];
double adjusted = t - (t - d);
return adjusted;
}
更新 2:时间
我进行了测试,发现 Dekker 的算法比 TWICE 快两倍!
Number of calls in test: 100,000,000
Unsafe Time = 1.922 (sec)
Safe Time = 0.799 (sec)
最佳答案
Dekker 的算法会将 float 拆分为高位和低位部分。如果有效数中有 s 位(IEEE 754 64 位二进制中为 53),则 *x0
接收高 s-b 位,这是您请求的,*x1
接收剩余的位,您可以丢弃这些位。在下面的代码中,Scale
的值应为 2b。如果 b 在编译时已知,例如常量 43,您可以将 Scale
替换为 0x1p43
。否则,您必须以某种方式生成 2b。
这需要舍入到最近的模式。 IEEE 754 算术就足够了,但其他合理的算术也可能没问题。它将关系舍入为偶数,这不是您所要求的(向上关系)。有必要吗?
这假设 x * (Scale + 1)
没有溢出。必须以 double (不大于)评估操作。
void Split(double *x0, double *x1, double x)
{
double d = x * (Scale + 1);
double t = d - x;
*x0 = d - t;
*x1 = x - *x0;
}
关于c# - 将 double 四舍五入到以位数给出的较低精度的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14285492/
面对这样的事实,MatPlotlib 在使用 self.frame.canvas.draw() 时,我在一个简单的图表上仅获得了 12 FPS。我发现一篇关于加速MatPlotlib的好文章:http
我的问题是我的 GameScene 以大约两倍的节点开始,并在几秒钟内绘制计数和 40 fps。这个问题仅出现在我的 iPad(迷你视网膜)上,而在我的 iPhone(5)上,游戏从一开始就运行得很顺
好吧,我开始理解 Android Fragments,但这仍然让我感到困惑。我需要一点帮助。正如它所说,Android fragment 从 API 级别 11 开始受支持,但您可以为较低级别的 AP
我正在尝试在 iPhone 上进行一些图像处理。我正在使用http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html捕获相机帧。 我的问
如果我没有以某种方式更新屏幕,对 canvas.repaint() 的几次调用似乎会被完全跳过。移动鼠标时,一切都很好。 我的代码如下: package yeet.gfxTut; import jav
我知道 android.utils.Base64 仅在 API level8 上可用,但我也听说过这个 Bouncy CaSTLe Base64(org.bouncycaSTLe.util.encod
也许我的逻辑暂时停止工作了,但我发现这种行为令人困惑。假设我有一个 TreeMap 如下: TreeMap map = new TreeMap(Collections.reverseOrder()
关于我的导航,我遇到的问题是第二层被视频或其他由 javascript 创建的元素覆盖(当您将鼠标悬停在“Hier lebe ich”或“Am Meer”时可见): http://www.ulrich
我最初在使用纹理时遇到了颜色困惑的问题,但我设法修复了它(问题是我没有在需要时禁用纹理)。完成此操作后,颜色发生了变化,但仍然不是我想要的颜色 - 白色而不是纯蓝色 (0,0,255) RGB。完整的
在我的游戏中,我在 render 中创建了许多循环和方法。我笔记本电脑的 FPS 范围从 56 到 60,没问题。但是,当我在 Galaxy Note 4 的 Android 操作系统中运行它时,FP
所以我今天一直在试验 z-index,我真的不明白这里发生了什么。 这是一个非常简化的 HTML 版本: // content has z-index of 30, pos abs // c
我用 2 个线程编写了小 WPF 应用程序 - 主线程是 GUI 线程,另一个线程是工作线程。 应用程序有一个带有一些控件的 WPF 表单。有一个按钮,允许选择目录。选择目录后,应用程序会扫描该目录中
我正在努力寻找适合我的数据集的学习算法。 我正在处理一个典型的回归问题。数据集中有 6 个我关心的特征。我的数据集中大约有 800 个数据点。这些特征和预测值具有很高的非线性相关性,因此这些特征并非无
这个问题在这里已经有了答案: Are Activity/Fragment Transitions compatible with pre-Lollipop devices? (4 个回答) 关闭 7
我正在尝试创建一个具有云形成的 AWS S3 存储桶。 S3 存储桶名称需要小写,但我想使用参数来组合该名称。该参数为大写。 我找到了一条路。 我读过这篇文章。 https://github.com/
这太奇怪了,尽管复制粘贴了代码,但我什至无法在 jsfiddle 中复制错误。 基本上我是这样的: 使用这个 CSS: .container { background: t
我是一名优秀的程序员,十分优秀!