我有一个简单的基于时间戳的表达式,它从JSONObject中提取值。以下是代码的摘录
Long cur_trig = Long.parseLong(api_content.get("timestamp").toString());
Long last_trig = Long.parseLong(trigger_info.get(key));
frequency = 60.0
if ( last_trig + frequency*1000 > cur_trig) {
System.out.println("Too early for an alert");
}
上述代码不符合if
条件,即使理论上是正确的。
Long curr_trig = 1455213601000L;
Long last_trig = 1455213600000L;
double freq = 60.0;
if (last_trig + freq * 1000 > curr_trig) {
System.out.println("Yup its correct");
}
在这种情况下,它完全正常。我已经手动打印了第一种情况下的值,数字确实加起来了。奇怪的是,我注意到,如果我手动对类值进行类型转换:
Long next_trig_time = (long) (last_trig + alert.frequency*1000);
if ( next_trig_time > cur_trig) {
System.out.println( "Its fine!");
}
这似乎工作正常。我无法理解的是,在评估表达式时,Java是否应自动将值转换为更高数据类型?或至少抛出警告/错误?
编辑1: 根据建议,我添加了以下内容
boolean notified = last_trig + alert.frequency*1000 > cur_trig ;
if (notified) {
System.out.println( "Its fine!");
}
与第一种情况相比,这没有任何区别。
编辑2:
使用long
代替Long
:
long last_trig = Long.parseLong(trigger_info.get(key));
long cur_trig = Long.parseLong(api_content.get("timestamp").toString());
frequency = 60.0
boolean notified = last_trig + frequency*1000 > cur_trig ;
if (notified) {
System.out.println( "Its fine!");
}
令人惊讶的是,即使这样也行不通。
编辑3: 这是一个可重现的问题
JSONObject js = new JSONObject();
js.put("last_trig","1455213601000");
js.put("cur_trig", "1455213600000");
Long last_trig = Long.parseLong(js.get("last_trig").toString());
Long cur_trig = Long.parseLong(js.get("cur_trig").toString());
float frequency = (float) 60.0;
Long next_trig_time = (long) (last_trig + frequency*1000);
if (last_trig + frequency*1000 > cur_trig) {
System.out.println("[Case 1] Too early for an alert");
}
else {
System.out.println("[Case 1] Too late for an alert");
}
if ( next_trig_time > cur_trig) {
System.out.println("[Case 2] Too early for an alert");
}
else {
System.out.println("[Case 2] Too late for an alert");
}
当前输出:
[案例1]警报太迟了 [案例2]警报太早
预期产出:
[案例1]警报太早了 [案例2]警报太早
答案 0 :(得分:1)
简短回答:java中的float没有足够的精度来做你想做的事。基本上,6-7有效数字是最大值。
解决方法,使用双打。
Long last_trig = Long.parseLong(js.get("last_trig").toString());
Long cur_trig = Long.parseLong(js.get("cur_trig").toString());
double frequency = 60.0;
double v = last_trig + frequency * 1000;
if (v > cur_trig) {
System.out.println("[Case 1] Too early for an alert");
}
else {
System.out.println("[Case 1] Too late for an alert");
}
Long next_trig_time = (long) v;
if ( next_trig_time > cur_trig) {
System.out.println("[Case 2] Too early for an alert");
}
else {
System.out.println("[Case 2] Too late for an alert");
}
[案例1]警报太早了 [案例2]警报太早
有趣的东西:
long l = 0x123456712345678L;
float d = l;
long lAgain = (long) d;
System.out.println(lAgain == l);
猜猜它打印的是什么?
答案 1 :(得分:0)
让我们比较两个代码片段:
你说这有用......:
Long curr_trig = 1455213601000L;
Long last_trig = 1455213600000L;
double freq = 60.0;
if (last_trig + freq * 1000 > curr_trig) {
System.out.println("Yup its correct");
}
......而且这失败了:
Long last_trig = Long.parseLong(js.get("last_trig").toString());
Long cur_trig = Long.parseLong(js.get("cur_trig").toString());
float frequency = (float) 60.0;
if (last_trig + frequency*1000 > cur_trig) {
System.out.println("[Case 1] Too early for an alert");
}
这里最重要的区别是frequency
的类型。它会影响last_trig + frequency*1000
的类型,而float
似乎无法正确处理您的号码。它会将结果视为1.45521364E12
(由于flating point inaccuracies,我认为它不是1.45521366E12
)。右侧也可能会“升级”为float
,以便对其进行比较(reference)和(float)cur_trig
也是1.45521366E12
。
你可以通过以下方式解决这个问题:
将frequency
更改为double
:
double frequency = 60.0;
投射到double
:
if (last_trig + (double)(frequency * 1000) > cur_trig) {
允许相等的值(因此将支持不准确的float
):
if (last_trig + frequency * 1000 >= cur_trig) {