最初我以为Math.Sign
将是正确的路,但经过一次测试后,它似乎将-0.0
和+0.0
视为相同。如何测试负数零?
Q
如何测试负数零?
36
A
回答
42
这里做的难看破解方法:
private static readonly long NegativeZeroBits =
BitConverter.DoubleToInt64Bits(-0.0);
public static bool IsNegativeZero(double x)
{
return BitConverter.DoubleToInt64Bits(x) == NegativeZeroBits;
}
基本上就为-0.0确切位模式测试,但不必硬编码。
14
经过一番搜索之后,我终于把它变成了C#规范的Section 7.7.2,并提出了这个解决方案。
private static bool IsNegativeZero(double x)
{
return x == 0.0 && double.IsNegativeInfinity(1.0/x);
}
8
负零具有符号位设置。因此:
public static bool IsNegativeZero(double value) {
if (value != 0) return false;
int index = BitConverter.IsLittleEndian ? 7 : 0;
return BitConverter.GetBytes(value)[index] == 0x80;
}
编辑:正如OP指出的,这在Release模式下不起作用。 x86 JIT优化器认真考虑if()语句并直接加载0,而不是加载值。这确实是更高性能的。但是这会导致消极的零点消失。该代码需要去调整,以防止这种情况:
public static bool IsNegativeZero(double value) {
int index = BitConverter.IsLittleEndian ? 7 : 0;
if (BitConverter.GetBytes(value)[index] != 0x80) return false;
return value == 0;
}
这是x86的抖动比较典型的行为顺便说一句,它不处理角落的情况非常好,当它优化浮点代码。在这方面,x64抖动要好得多。虽然可以说没有比赋予负数零的含义更糟糕的角落案例。预先警告。
7
这是另一个黑客。它利用了一个事实,即Equals
上一个struct
会做的,而不是呼吁其成员Equals
按位比较:
struct Negative0
{
double val;
public static bool Equals(double d)
{
return new Negative0 { val = -0d }.Equals(new Negative0 { val = d });
}
}
Negative0.Equals(0); // false
Negative0.Equals(-0.0); // true
8
x == 0 && 1/x < 0
1
更一般地,你可以做,
bool IsNegative(double value)
{
const ulong SignBit = 0x8000000000000000;
return ((ulong)BitConverter.DoubleToInt64Bits(value) & SignBit) == SignBit;
}
或替代,如果你愿意,
[StructLayout(LayoutKind.Explicit)]
private struct DoubleULong
{
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public readonly ulong ULong;
}
bool IsNegative(double value)
{
var du = new DoubleULong { Double = value };
return ((du.ULong >> 62) & 2) == 2;
}
后来给出了调试,但大约50%的性能改良效果。一旦在释放模式下编译并从命令行运行,则没有显着差异。
我无法使用不安全的代码生成性能改进,但这可能是由于我缺乏经验。
相关问题
- 1. 如何用零替换excel负数?
- 2. 如何完成负载测试
- 3. 如何配置SoapUI负载测试?
- 4. 如何测试UITextField是否为零?
- 5. 如何在Windows中运行Apache基准测试负载测试?
- 6. SoapUi负载测试
- 7. WCF负载测试
- 8. JMeter负载测试
- 9. JUnit测试(正面和负面测试)
- 10. 负载测试csript intern.js内测试
- 11. TFS负载测试Web测试
- 12. 负载测试工具的负载测试能力
- 13. Ruby测试::的单元测试零SimpleDelegator
- 14. 零宽度负向预测声明如何在R中工作?
- 15. 将负数设为零Powershell
- 16. 负载测试vuser负载亚军11
- 17. 在运行Web测试时参数化负载测试?
- 18. VS负载测试没有数据库
- 19. 负载测试数据库实例
- 20. 如何参数化在肥皂UI负载测试
- 21. 如何使用LoadUI执行数据驱动的负载测试
- 22. 性能测试vs负载测试vs压力测试
- 23. 如何测试多个输入以检测负数,同时记录哪些输入是负数?
- 24. 负载测试Vaadin 6.3.4
- 25. 负载测试工具IIS6 +
- 26. mysql负载测试工具
- 27. PayPal Express Checkout负面测试
- 28. Asp.net网站负载测试
- 29. VSTS负载测试报告
- 30. Gatling负载测试脚本
什么是*负零*,它与*正零*有什么不同?它与零* *有什么不同?在数学上它们是相同的。 * IEEE 754ically *可能不是。 – 2011-01-19 19:37:57
按位,-0.0的表示与+0.0有什么不同? 0x800000和0x000000? – Davidann 2011-01-19 19:39:31
@Darin Dimitrov,你有没有参加过数学分析课程? :P – 2011-01-19 19:39:42