【发布时间】:2018-07-09 17:52:33
【问题描述】:
我在 cudnnBatchNormalizationForwardTraining 函数中使用 CUDNN_BN_MIN_EPSILON 值时遇到了问题(请参阅 the docs here),事实证明这是因为我传递了 float 值 1e-5f 而不是 double(我'正在使用 float 值以节省内存并加快计算速度),并且该值一旦转换为浮点数就略小于 1e-5,这是该常量的实际值。
经过反复试验,我找到了一个不错的近似值:
const float CUDNN_BN_MIN_EPSILON = 1e-5f + 5e-13f;
我确信有更好的方法来解决这样的问题,所以问题是:
给定一个正的
double值,找到最小可能的float值的最佳(如“可靠”)方法是什么(单独和如果/当转换为double时)严格更大比最初的double值?
另一种表述这个问题的方法是,给定一个double 值d1 和一个float 值f1,d1 - (float)f1 应该是最小可能的 negative 值(如否则,这意味着f1 小于 d1,这不是我们想要的)。
我做了一些基本的试验和错误(使用1e-5 作为我的目标值):
// Check the initial difference
> 1e-5 - 1e-5f
2,5262124918247909E-13 // We'd like a small negative value here
// Try to add the difference to the float value
> 1e-5 - (1e-5f + (float)(1e-5 - 1e-5f))
2,5262124918247909E-13 // Same, probably due to approximation
// Double the difference (as a test)
> 1e-5 - (1e-5f + (float)((1e-5 - 1e-5f) * 2))
-6,5687345259044915E-13 // OK
使用这个近似值,最终的float 值为1,00000007E-05,看起来不错。
但是,* 2 乘法对我来说完全是任意的,我不确定它是否可靠或在那里做的最佳可能的事情。
有没有更好的方法来实现这一点?
谢谢!
编辑:这是我现在使用的(坏)解决方案,很乐意用更好的解决方案替换它!
/// <summary>
/// Returns the minimum possible upper <see cref="float"/> approximation of the given <see cref="double"/> value
/// </summary>
/// <param name="value">The value to approximate</param>
public static float ToApproximatedFloat(this double value)
=> (float)value + (float)((value - (float)value) * 2);
解决方案:这是最终的正确实现(感谢 John Bollinger):
public static unsafe float ToApproximatedFloat(this double value)
{
// Obtain the bit representation of the double value
ulong bits = *((ulong*)&value);
// Extract and re-bias the exponent field
ulong exponent = ((bits >> 52) & 0x7FF) - 1023 + 127;
// Extract the significand bits and truncate the excess
ulong significand = (bits >> 29) & 0x7FFFFF;
// Assemble the result in 32-bit unsigned integer format, then add 1
ulong converted = (((bits >> 32) & 0x80000000u)
| (exponent << 23)
| significand) + 1;
// Reinterpret the bit pattern as a float
return *((float*)&converted);
}
【问题讨论】:
-
请指定您的语言。例如,在 C++ 中有一个库函数。其他的就不知道了。
-
如何查看双精度的内存表示,将位削减为浮点数,然后在最低有效位上加 1?
-
@Rakete1111 我正在使用 C#(通过包装器使用 cuDNN),但我正在寻找一个通用的、独立的解决方案(为了理解它,而不仅仅是使用帮助库) .
-
@Sergio0694 那么language-agnostic 不是更好的标签吗?
-
请注意,在 C 中,
(ulong*)&value可能是 UB(C11dr §6.3.2.3 7)。好奇的代码没有使用@John Bollinger 建议的memcpy()
标签: c# c++ c floating-point