【问题标题】:Inverting digits of a hex value反转十六进制值的数字
【发布时间】:2012-07-16 18:56:00
【问题描述】:

我需要取十六进制数中的所有数字并“反转”它们:所有零都变成非零 (F),所有非零都变成零。

我试过了:

void someFunction(DWORD hexVal)
{
     //...
     hexVal = ~hexVal;
     //...
}

这将 0xE0000000 更改为 0x1FFFFFFF 而不是 0x0FFFFFFF。

我怎样才能产生想要的结果?

【问题讨论】:

  • 0xE0000000 不是 0x00000000?
  • @TheZ 我知道,调用函数的程序通过了0xE0000000
  • @jli non-zero 取反后不一定是 F,可以是任意非零值。零以外的任何东西都需要变成零
  • 0xE0000000 = 1110 0000 0000 0000 0000 0000 0000 0000 ~0xE0000000 = 0001 1111 1111 1111 1111 1111 1111 1111 = 0x1FFFFFFF
  • 在我看来,您需要在一个循环中获取这些四重奏并单独处理它们

标签: c++ hex


【解决方案1】:

假设您真的是想要零->非零,反之亦然,逐位计算:

DWORD invertDigits(DWORD in) {
    return (
        ((in & (0xF << 28)) ? 0x0 : (0xF << 28)) |
        ((in & (0xF << 24)) ? 0x0 : (0xF << 24)) |
        ((in & (0xF << 20)) ? 0x0 : (0xF << 20)) |
        ((in & (0xF << 16)) ? 0x0 : (0xF << 16)) |
        ((in & (0xF << 12)) ? 0x0 : (0xF << 12)) |
        ((in & (0xF << 8)) ? 0x0 : (0xF << 8)) |
        ((in & (0xF << 4)) ? 0x0 : (0xF << 4)) |
        ((in & (0xF << 0)) ? 0x0 : (0xF << 0))
    );
}

【讨论】:

  • 你的移动速度不够。位转换。 :D
【解决方案2】:

这是按位非运算的预期结果。 0xE0000000 + 0x1FFFFFFF = 0xFFFFFFFF

绝对最快的方法是将其拆分为字节并使用查找表。

此解决方案使用的处理器相当于大约:24 次加法、4 次乘法和 4 次内存查找。乘法是数组索引的一部分。所有简单的数学运算都以大致相同的速度运行,除了乘法和内存查找稍长一些。您的里程可能会因您的处理器架构和执行的编译器优化而异。

unsigned int transform1(unsigned int value)
{
    // static const unsigned char ZZ = 0x0, ZF = 0xF, FZ = 0xF0, FF = 0xFF; // for C++

    #define ZZ (unsigned char) 0x00
    #define FZ (unsigned char) 0xF0
    #define ZF (unsigned char) 0x0F
    #define FF (unsigned char) 0xFF

    static const unsigned char lookup[256] = 
    {
        FF, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
        ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
    }; // array takes up 1KB of RAM

    unsigned int result = 0;

    result |= lookup[(unsigned int)((value & (FF << 0 )) >> 0) ] << 0;
    result |= lookup[(unsigned int)((value & (FF << 8 )) >> 8) ] << 8;
    result |= lookup[(unsigned int)((value & (FF << 16)) >> 16)] << 16;
    result |= lookup[(unsigned int)((value & (FF << 24)) >> 24)] << 24;
    return result;
}

【讨论】:

  • 这在语法上不太有效。有时。这取决于编译器认为 const 是怎样的。
  • 那里,现在它符合 C 标准。主要是。
  • 这在你的机器上运行速度有多快?
  • 没有线索。我正在运行 windows atm,因为 linux 和 amd 拒绝合作。然而,在我所做的网络测试中,它在大约 0.55 秒内运行了 100m 次迭代。该问题的 cmets 中有一个测试链接,只需克隆它并使用变换功能即可。我很惊讶,当我看到它时,我以为你会更快。
  • 出于无聊,我尝试了一个 16 位查找表,它在所有解决方案中运行速度最快,100m 轮运行时间略低于 0.4 秒(10 亿轮运行时间为 3.97 秒) .我在运行时初始化了查找表,这增加了一次额外的性能损失。如果有人好奇:ideone.com/64XFe
【解决方案3】:

所以反转和否定是两个不同的东西。

反相取每一位并产生它的补码,如下所示:

 0xE0000000 = 1110 0000 0000 0000 0000 0000 0000 0000
~0xE0000000 = 0001 1111 1111 1111 1111 1111 1111 1111 = 0x1FFFFFFF

如果你想要“除了零之外的任何东西都需要变成零”你想要布尔否定,即

hexVal = !hexVal;

编辑:好的,在阅读了其他一些答案后,我终于明白了提问者的问题,这是我使用一个巨大位数学表达式的个人版本

n = ~(n | ((n & 0x77777777) << 1) | ((n & 0x88888888) >> 3)
        | ((n & 0x33333333) << 2) | ((n & 0xCCCCCCCC) >> 2)
        | ((n & 0x11111111) << 3) | ((n & 0xEEEEEEEE) >> 1));

【讨论】:

  • 似乎返回了正确答案。不过,我并没有彻底测试它。在 0.8 秒内运行 1 亿次迭代。
【解决方案4】:

这应该会为您提供 2 个字节的所需结果。你明白 4 个字节的想法。

hexval = ((hexval & 0xf000) ? 0 : 0xf000) |
         ((hexval & 0xf00) ? 0 : 0xf00) |
         ((hexval & 0xf0) ? 0 : 0xf0) |
         ((hexval & 0xf) ? 0 : 0xf);

【讨论】:

  • 1 亿次迭代大约需要 1.2 秒。 Han Z' 的解决方案稍快。
  • @Wug 导致 bitmath 和 bitshift > 分支 ;)
  • 这 1.2 秒是几次运行的平均值吗(因为运行的其他程序会影响它)?我不担心每次迭代使用 1.2 * 10^-8 (在您的平台/操作系统上/取决于正在运行的其他内容)。您的程序可能会提高其他地方的性能。
【解决方案5】:

您可能必须逐个字节,从 MSB 开始。检查该值是否在 16^6 和 16^7 之间(假设这是无符号的)。如果是,加到新数0。如果不是,加到新数2^31+2^30+2^29+2^28。

看看我在说什么?

【讨论】:

    猜你喜欢
    • 2018-07-26
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2018-01-22
    • 2021-08-01
    • 2014-01-29
    • 1970-01-01
    • 2021-11-26
    相关资源
    最近更新 更多