当前位置: 首页 > 知识库问答 >
问题:

针对SSE2之前处理器的Java运行时如何实现浮点基本运算?

东郭承业
2023-03-14

当设置strictfp时,针对没有SSE2的英特尔处理器的Java运行时如何处理浮点非规格化?

即使 387 FPU 设置为 53 位精度,它也会保持超大的指数范围:

  1. 强制检测每个中间结果的下限溢位/溢出,并且
  2. 使得它很难避免二次四舍五入。

策略包括重新计算导致具有仿真浮点的反规范值的操作,或者沿着该技术的路线的永久指数偏移,以给OCaml配备63位浮点,从指数借用一位以避免双重舍入。

无论如何,我认为没有办法避免每个浮点计算至少有一个条件分支,除非可以静态确定该操作不下溢/溢出。如何处理特殊(溢出/下溢)情况是我问题的一部分,但这不能与表示问题分开(例如,永久指数偏移策略似乎意味着只需要检查溢出)。

共有1个答案

强安和
2023-03-14

在我看来,从一个非常微不足道的测试用例来看,就像 JVM 在内存中每次重复计算一次往返以获得它想要的舍入一样。它似乎也用几个魔术常数做了一些奇怪的事情。以下是它为我做了一个简单的“天真地计算 2^n”程序:

0xb1e444b0: fld1
0xb1e444b2: jmp    0xb1e444dd         ;*iload
                                      ; - fptest::calc@9 (line 6)
0xb1e444b7: nop
0xb1e444b8: fldt   0xb523a2c8         ;   {external_word}
0xb1e444be: fmulp  %st,%st(1)
0xb1e444c0: fmull  0xb1e44490         ;   {section_word}
0xb1e444c6: fldt   0xb523a2bc         ;   {external_word}
0xb1e444cc: fmulp  %st,%st(1)
0xb1e444ce: fstpl  0x10(%esp)
0xb1e444d2: inc    %esi               ; OopMap{off=51}
                                      ;*goto
                                      ; - fptest::calc@22 (line 6)
0xb1e444d3: test   %eax,0xb3f8d100    ;   {poll}
0xb1e444d9: fldl   0x10(%esp)         ;*goto
                                      ; - fptest::calc@22 (line 6)
0xb1e444dd: cmp    %ecx,%esi
0xb1e444df: jl     0xb1e444b8         ;*if_icmpge
                                      ; - fptest::calc@12 (line 6)

我相信< code>0xb523a2c8和< code>0xb523a2bc是热点源代码中的< code > _ fpu _ subnormal _ bias 1 和< code > _ fpu _ subnormal _ bias 2 。< code > _ fpu _ subnormal _ bias 1 看起来是< code > 0x 03 ff 80000000000000 ,而< code > _ fpu _ subnormal _ bias 2 看起来是< code > 0x 7 BFF 800000000000000 。< code > _ fpu _ subnormal _ bias 1 具有将最小正常< code>double缩放到最小正常< code>long double的效果;如果FPU舍入到53位,就会发生“正确的事情”。

我推测看似毫无意义的testhtml" target="_blank">指令存在,因此可以通过在需要GC的情况下标记该页面不可读来中断线程

下面是Java代码:

import java.io.*;
public strictfp class fptest {
 public static double calc(int k) {
  double a = 2.0;
  double b = 1.0;
  for (int i = 0; i < k; i++) {
   b *= a;
  }
  return b;
 }
 public static double intest() {
  double d = 0;
  for (int i = 0; i < 4100; i++) d += calc(i);
  return d;
 }
 public static void main(String[] args) throws Exception {
  for (int i = 0; i < 100; i++)
   System.out.println(intest());
 }
}

进一步挖掘,这些操作的代码在hotpot/src/cpu/x86/vm/x86_63.ad中的OpenJDK代码中显而易见。相关片段:

instruct strictfp_mulD_reg(regDPR1 dst, regnotDPR1 src) %{
  predicate( UseSSE<=1 && Compile::current()->has_method() && Compile::current()
->method()->is_strict() );
  match(Set dst (MulD dst src));
  ins_cost(1);   // Select this instruction for all strict FP double multiplies

  format %{ "FLD    StubRoutines::_fpu_subnormal_bias1\n\t"
            "DMULp  $dst,ST\n\t"
            "FLD    $src\n\t"
            "DMULp  $dst,ST\n\t"
            "FLD    StubRoutines::_fpu_subnormal_bias2\n\t"
            "DMULp  $dst,ST\n\t" %}
  opcode(0xDE, 0x1); /* DE C8+i or DE /1*/
  ins_encode( strictfp_bias1(dst),
              Push_Reg_D(src),
              OpcP, RegOpc(dst),
              strictfp_bias2(dst) );
  ins_pipe( fpu_reg_reg );
%}

instruct strictfp_divD_reg(regDPR1 dst, regnotDPR1 src) %{
  predicate (UseSSE<=1);
  match(Set dst (DivD dst src));
  predicate( UseSSE<=1 && Compile::current()->has_method() && Compile::current()
->method()->is_strict() );
  ins_cost(01);

  format %{ "FLD    StubRoutines::_fpu_subnormal_bias1\n\t"
            "DMULp  $dst,ST\n\t"
            "FLD    $src\n\t"
            "FDIVp  $dst,ST\n\t"
            "FLD    StubRoutines::_fpu_subnormal_bias2\n\t"
            "DMULp  $dst,ST\n\t" %}
  opcode(0xDE, 0x7); /* DE F8+i or DE /7*/
  ins_encode( strictfp_bias1(dst),
              Push_Reg_D(src),
              OpcP, RegOpc(dst),
              strictfp_bias2(dst) );
  ins_pipe( fpu_reg_reg );
%}

我看不到任何加法和减法,但我敢打赌,他们只是在53位模式下用FPU做一个加法/减法,然后在内存中来回传递结果。我有点好奇是否有一个棘手的溢出情况,他们得到了错误的,但我没有好奇到找出答案。

 类似资料:
  • 问题内容: 设置时,针对没有SSE2的英特尔处理器的Java运行时如何处理浮点异常? 即使将387 FPU设置为53位精度,它也会保留以下指数范围: 强制在每个中间结果处检测下溢/上溢,并且 很难避免异常值的二舍五入。 策略包括重新计算导致模拟浮点数为非正规值的运算,或者沿此技术的路线使用永久指数偏移量,以为OCaml配备63位浮点数,并从指数中借用一点以避免重复-四舍五入。 无论如何,我认为没有

  • 本文向大家介绍Shell脚本处理浮点数的运算和比较实例,包括了Shell脚本处理浮点数的运算和比较实例的使用技巧和注意事项,需要的朋友参考一下 通过top命令看到的进程的CPU、内存的使用率的百分比是一个浮点数,我需要在写脚本时对其进行处理,所以学习了一些,总结如下。 其实,Shell(这里是Bash)本身不具备处理浮点计算的能力,但是可以使用“bc”这个高精度的计算器工具来帮助,另外,也可以在B

  • 本文向大家介绍Javascript实现基本运算器,包括了Javascript实现基本运算器的使用技巧和注意事项,需要的朋友参考一下 用Javascript实现一个基本的运算器,具体内容如下 使用表格布局,JS添加事件 计算器的”c”功能为清屏;”d”功能为删除一个数; 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 问题内容: 我正在尝试从Java代码运行批处理文件 这是批处理文件行: 当我从代码中运行批处理文件时, “ 1” 随机出现在“ >>”之前。所以cmd中的行变成这样: 我不知道如何删除此随机出现的“ 1” 这就是我从代码中运行批处理文件的方式 问题答案: 首先,使用命令重定向运算符查看Microsoft的TechNet文章。 数值 1 与handle stdout (标准输出)等效。 在批处理文件

  • 本文向大家介绍C#浮点数的表示和基本运算,包括了C#浮点数的表示和基本运算的使用技巧和注意事项,需要的朋友参考一下 1 浮点数的表示 通常,我们可以用下面的格式来表示浮点数 S P M 其中S是符号位,P是阶码,M是尾数 对于IBM-PC而言,单精度浮点数是32位(即4字节)的,双精度浮点数是64位(即8字节)的。两者的S,P,M所占的位数以及表示方法由下表可知 S P M 表示公式 偏移量 1

  • 本文向大家介绍pandas针对excel处理的实现,包括了pandas针对excel处理的实现的使用技巧和注意事项,需要的朋友参考一下 本文主要介绍了pandas针对excel处理的实现,分享给大家,具体如下: 读取文件 数值处理 获取数据 loc和iloc详解 多行 输出行号和列号 获取指定值 基本格式化 数据多表合并 到此这篇关于pandas针对excel处理的实现的文章就介绍到这了,更多相关

  • 问题内容: 我对在Go中精确减去2个float的方法感兴趣。 我尝试使用该 库,但无法获得准确的结果。 我使用Javascript中的big.js库解决了此问题。Go算法是否有类似的库/方法? https://play.golang.org/p/vomAr87Xln 问题答案: 包装大 导入“数学/大” func(* Float)字符串 字符串格式x类似于x.Text(’g’,10)。(必须显式调

  • 我阅读关于浮点和舍入在浮点算术期间发生的错误。 我读了很多关于IEEE754单精度/双精度格式的文章。我知道有符号位、8(或)11位指数和23(或)52位有效位以及隐式前导位。 我也知道分母不是质因数2的实数不能完全表示,例如二进制中的0.1是0.0001100110011...... 我知道0.1 0.1 0.1不等于0.3,因为舍入误差的累积。 同样,0.5也可以用二进制格式表示,因为它是1/