是否有更快的方法将十六进制小数部分转换为十进制小数?

如何解决是否有更快的方法将十六进制小数部分转换为十进制小数?

我编写了一个程序,该程序以十六进制生成pi的数字。我经常以基准值将我拥有的十六进制值转换为十进制值并将其保存到文件中。目前,我正在使用BigDecimal通过以下代码进行该数学运算:

private static String toDecimal(String hex) {
    String rawHex = hex.replace(".","");
    BigDecimal base = new BigDecimal(new BigInteger(rawHex,16));
    BigDecimal factor = new BigDecimal(BigInteger.valueOf(16).pow(rawHex.length() - 1));
    BigDecimal value = base.divide(factor);
    return value.toPlainString().substring(0,hex.length());
}

请注意,此方法仅适用于整数部分中包含一位的十六进制值(包括pi),请勿将其复制和粘贴以用于一般用途。

因此,此代码可以正常工作,但对于最新的基准测试(250万位),转换需要11.3个小时才能完成。

有没有更快的手动方法?

我尝试将第一个小数位除以16,将第二个小数除以16 ^ 2,依此类推,但是这样很快就会失去控制。也许可以通过某种方式将数字移回以保持除数很低?但是可能需要处理n + 1,n + 2,n + 3等数字才能获得n的正确值。

解决方法

首先,我认为您的函数toDecimal是错误的,例如,它无法正确转换输入".1a"(相差16倍),并为输入{{ 1}}。第三行应该是:

".800"

该异常源于:

BigDecimal factor = new BigDecimal(BigInteger.valueOf(16).pow(rawHex.length()));

转换后的值可能比输入值短,您会得到return value.toPlainString().substring(0,hex.length());

继续前进:

实际上,我尚未针对您当前的方法进行基准测试;我只是将此作为“深思熟虑”。在这里,我正在做乘法,因为孩子在学校被教做乘法。在您的情况下,我们有一个很大的循环只能产生一位数字。但是,如果您可以通过某种方式使其适应使用BigDecimal(尚不清楚如何使用),则它可能比当前方法要快(真正需要的是BigHexadecimal类)。

可以观察到,可以使用乘法将分数从一个碱基转换为另一个碱基。在这种情况下,我们具有以下十六进制分数(我们可以忽略整数部分,即在转换pi时为3):

.h 1 h 2 h 3 h 4 ... h n

其中 h n 是第n个个十六进制“半字节”。

我们希望将以上内容转换为以下十进制分数:

.d 1 d 2 d 3 d 4 ... d n

其中 d n 是第n 个十进制数字。

如果将两个数量乘以10,我们将得到:

h ' 1 .h ' 2 h ' 3 h ' 4 ... h ' n
质数(`)表示乘法后我们有了全新的十六进制半字节值。

d 1 .d 2 d 3 d 4 ... d n
乘以10只会将小数部分向左移动一位。

我们必须注意,小数点左边的数量必须相等,即 d 1 == h ' 1 。因此,我们将十六进制分数重复乘以10,每次执行时,我们都会将整数部分作为下一个十进制数字进行转换。我们重复此过程,直到新的十六进制分数变为0或产生了任意数量的十进制数字为止:

See Java Demo

java.lang.StringIndexOutOfBoundsException

打印:

class Test {

    private static String toDecimal(String hex,int numberDigits) {
        /* converts a string such as "13.1a" in base 16 to "19.1015625" in base 10 */
        int index = hex.indexOf('.');
        assert index != -1;
        StringBuilder decimal = new StringBuilder((index == 0) ? "" : String.valueOf(Integer.parseInt(hex.substring(0,index),16)));
        decimal.append('.');
        int l = hex.length() - index - 1;
        assert l >= 1;
        int firstIndex = index + 1;
        int hexDigits[] = new int[l];
        for (int i = 0; i < l; i++) {
            hexDigits[i] = Integer.parseInt(hex.substring(i + firstIndex,i + firstIndex + 1),16);
        }
        while (numberDigits != 0 && l != 0) {
            int carry = 0;
            boolean allZeroes = true;
            for (int i = l - 1; i >= 0; i--) {
                int value = hexDigits[i] * 10 + carry;
                if (value == 0 && allZeroes) {
                    l = i;
                }
                else {
                    allZeroes = false;
                    carry = (int)(value / 16);
                    hexDigits[i] = value % 16;
                }
            }
            numberDigits--;
            if (carry != 0 || (numberDigits != 0 && l != 0))
                decimal.append("0123456789".charAt(carry));
        }
        return decimal.toString();
    }

    public static void main(String[] args) {
        System.out.println(toDecimal("13.1a",15));
        System.out.println(toDecimal("13.8",15));
        System.out.println(toDecimal("13.1234",15));
    }

}
,

感谢@Booboo解决此问题。我对他的代码做了一些改进,因此在每种情况下都可以使用。我想在这里张贴给以后的访客。

/**
 * Converts a hex number string to a decimal number string.
 *
 * @param hex      The hex number string.
 * @param accuracy The number of decimal places to return in the decimal number string.
 * @return The decimal number string.
 */
public static String hexToDecimal(String hex,int accuracy) {
    if (!hex.matches("[0-9A-Fa-f.\\-]+") || (accuracy < 0)) {
        return "";
    }
    
    boolean negative = hex.startsWith("-");
    hex = hex.replaceAll("^-","");
    String integral = hex.contains(".") ? hex.substring(0,hex.indexOf(".")) : hex;
    String fraction = hex.contains(".") ? hex.substring(hex.indexOf(".") + 1) : "";
    if (integral.contains("-") || fraction.contains(".") || fraction.contains("-")) {
        return "";
    }
    
    StringBuilder decimal = new StringBuilder();
    decimal.append(negative ? "-" : "");
    decimal.append(integral.isEmpty() ? "0" : new BigDecimal(new BigInteger(integral,16)).toPlainString());
    if (fraction.isEmpty() || (accuracy == 0)) {
        return decimal.toString();
    }
    decimal.append(".");
    
    int numberDigits = accuracy;
    int length = Math.min(fraction.length(),numberDigits);
    int[] hexDigits = new int[numberDigits];
    Arrays.fill(hexDigits,0);
    IntStream.range(0,length).boxed().parallel().forEach(i -> hexDigits[i] = Integer.parseInt(String.valueOf(fraction.charAt(i)),16));
    
    while ((numberDigits != 0)) {
        int carry = 0;
        for (int i = length - 1; i >= 0; i--) {
            int value = hexDigits[i] * 10 + carry;
            carry = value / 16;
            hexDigits[i] = value % 16;
        }
        decimal.append(carry);
        numberDigits--;
    }
    return decimal.toString();
}

/**
 * Converts a hex number string to a decimal number string.
 *
 * @param hex The hex number string.
 * @return The decimal number string.
 * @see #hexToDecimal(String,int)
 */
public static String hexToDecimal(String hex) {
    String fraction = hex.contains(".") ? hex.substring(hex.indexOf(".") + 1) : "";
    return hexToDecimal(hex,fraction.length());
}

public static void main(String[] args) {
    //integer
    Assert.assertEquals("0",hexToDecimal("0"));
    Assert.assertEquals("1",hexToDecimal("1"));
    Assert.assertEquals("9",hexToDecimal("9"));
    Assert.assertEquals("15",hexToDecimal("F"));
    Assert.assertEquals("242",hexToDecimal("F2"));
    Assert.assertEquals("33190",hexToDecimal("81A6"));
    Assert.assertEquals("256",hexToDecimal("100"));
    Assert.assertEquals("1048576",hexToDecimal("100000"));
    Assert.assertEquals("5191557193152165532727847676938654",hexToDecimal("FFF6AA0322BC458D5D11A632099E"));
    Assert.assertEquals("282886881332428154466487121231991859970997056152877088222",hexToDecimal("B897A12C89896321C454A7DD9E150233CBB87A9F0233DDE"));
    Assert.assertEquals("-256",hexToDecimal("-100"));
    Assert.assertEquals("-144147542",hexToDecimal("-8978456"));
    Assert.assertEquals("-332651442596728389665499138728075237402",hexToDecimal("-FA42566214321CC67445D58EE874981A"));
    Assert.assertEquals("33190",hexToDecimal("81a6"));

    //decimal
    Assert.assertEquals("0.10",hexToDecimal("0.1a"));
    Assert.assertEquals("0.5",hexToDecimal("0.8"));
    Assert.assertEquals("0.0711",hexToDecimal("0.1234"));
    Assert.assertEquals("0.528966901",hexToDecimal("0.876A5FF4A"));
    Assert.assertEquals("-0.528966901",hexToDecimal("-0.876A5FF4A"));
    Assert.assertEquals("-0.00000000",hexToDecimal("-0.00000001"));
    Assert.assertEquals("-0.62067648792835838863907521427468",hexToDecimal("-0.9EE4A7810C666FF7453D06A44621030E"));
    Assert.assertEquals("0.528966901",hexToDecimal("0.876a5ff4a"));
    Assert.assertEquals("0.528966901",hexToDecimal(".876a5ff4a"));
    Assert.assertEquals("-0.528966901",hexToDecimal("-.876a5ff4a"));

    //combined
    Assert.assertEquals("15.33693",hexToDecimal("F.56412"));
    Assert.assertEquals("17220744.33934412",hexToDecimal("106C488.56DF41A2"));
    Assert.assertEquals("282886881332428154466487121231991859970997056152877088222.62067648792835838863907521427468",hexToDecimal("B897A12C89896321C454A7DD9E150233CBB87A9F0233DDE.9EE4A7810C666FF7453D06A44621030E"));
    Assert.assertEquals("-17220744.33934412",hexToDecimal("-106C488.56DF41A2"));
    Assert.assertEquals("-282886881332428154466487121231991859970997056152877088222.62067648792835838863907521427468",hexToDecimal("-B897A12C89896321C454A7DD9E150233CBB87A9F0233DDE.9EE4A7810C666FF7453D06A44621030E"));
    Assert.assertEquals("-17220744.33934412",hexToDecimal("-106c488.56df41a2"));
    Assert.assertEquals("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808",hexToDecimal("3.243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01377BE5466CF34E90C6CC0AC29B7C97"));

    //accuracy
    Assert.assertEquals("-0.00000",hexToDecimal("-0.00000001",5));
    Assert.assertEquals("-0.000000000232830",15));
    Assert.assertEquals("-0",0));
    Assert.assertEquals("282886881332428154466487121231991859970997056152877088222.5",hexToDecimal("B897A12C89896321C454A7DD9E150233CBB87A9F0233DDE.9EE4A7810C666FF7453D06A44621030E",1));
    Assert.assertEquals("3.14",hexToDecimal("3.243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01377BE5466CF34E90C6CC0AC29B7C97",2));
    Assert.assertEquals("3.1415926535",10));
    Assert.assertEquals("3.1415926535897932384626433",25));

    //invalid
    Assert.assertEquals("",hexToDecimal("0.00000.001"));
    Assert.assertEquals("",hexToDecimal("0.00000-001"));
    Assert.assertEquals("",hexToDecimal("156-081.00000001"));
    Assert.assertEquals("",hexToDecimal("hello"));
    Assert.assertEquals("",hexToDecimal("9g"));
    Assert.assertEquals("",hexToDecimal("9G"));
    Assert.assertEquals("",hexToDecimal("546.FDA",-1));
    Assert.assertEquals("",-999));
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-