向零舍入到最接近的 0x50 的简短按位方法?

2024-04-09

我正在尝试修补一个旧的 8 位汇编程序例程(它恰好是 M6800,但这并不是真正特定于机器的)以获取 16 位值并向下舍入到最接近的 0x50(dec 80)倍数。当前代码截断为最接近的32只需做一件事AND 0xE0到低字节,这当然会将低 5 位清零,并在不触及高字节的情况下获得正确的结果。

这是进行一些屏幕数学运算,因此输入值仅在以下范围内0xE000 to 0xE7CF。由于 80 显然不是 2 的幂,所以我不能简单地做到这一点,但考虑到这是一个补丁,我试图将指令数量保持在最低限度,理想情况下不添加通用除法或查找表等。

我很困惑,怀疑没有特别聪明的方法来实现这一点。 80 不是 2 的幂,而是 16 的倍数……这对我一点帮助都没有吗?任何见解、指示等都将受到赞赏。谢谢。


首先,自从80 = 16 * 5, 向下舍入为倍数80表示向下舍入为两者的倍数16 and 5。第一个很容易右移,所以现在我们只剩下mod 5 part:

def mod5(x):
    return x % 5

def round80(x):
    x >>= 4
    x -= mod5(x)
    x <<= 4
    return x

mod5不是那么容易做到的,但是有一个梅森模的巧妙构造 http://homepage.cs.uiowa.edu/%7Ejones/bcd/mod.shtml#exmod5首先计算mod15,然后将值降低到模 5。一开始并不是那么直观,但它只涉及加法和移位,这应该很容易实现。这是Python版本:

def mod15(x):
    x = (x >> 8) + (x & 0xFF)
    x = (x >> 4) + (x & 0xF)
    if x >= 15: x -= 15
    if x >= 15: x -= 15 # (see note)
    return x

def mod5(x):
    x = mod15(x)
    if x >= 5: x -= 5
    if x >= 5: x -= 5
    return x

def round80(x):
    x >>= 4
    x -= mod5(x)
    x <<= 4
    return x

为了安全起见,我验证了此代码的所有可能值:

for i in range(0x10000):
    trivial = i - (i % 80)
    assert trivial == round80(i)

补充一点:第二个if代替mod15实际上可以省略对于您的输入范围,注释掉没有什么区别。如果你需要整个[0,0xffff]范围内,则无法将其删除。

我不是 M6800 汇编方面的专家,所以我不会尝试编写最终代码,但它应该相对简单,特别是考虑到唯一的 16 位操作是两次移位和第一次加法mod15.

没有除法,没有乘法,也没有查找表 - 我希望这足够短,可以满足您的需求!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

向零舍入到最接近的 0x50 的简短按位方法? 的相关文章

  • 取消的分支与常规分支有何不同?

    特别是对于 SPARC Assembly 取消的分支与常规分支有何不同 我一直认为 当我需要填充分支指令的 nop 延迟槽时 需要取消分支指令 但是 我认为我在这一部分上是不正确的 因为您可以在不取消分支的情况下填充 nop 如果不采用分支
  • NASM 轮班操作员

    您将如何在寄存器上进行 NASM 中的位移位 我读了手册 它似乎只提到了这些操作员 gt gt lt lt 当我尝试使用它们时 NASM 抱怨移位运算符处理标量值 您能解释什么是标量值并举例说明如何使用 gt gt and lt lt 另外
  • 为什么 Visual Studio 使用 xchg ax,ax

    我正在查看程序的反汇编 因为它崩溃了 并注意到很多 xchg ax ax 我用谷歌搜索了一下 发现它本质上是一个 nop 但是为什么 Visual Studio 会执行 xchg 而不是 noop 该应用程序是一个C NET3 5 64位应
  • 近调用/跳转表并不总是在引导加载程序中工作

    一般问题 我一直在开发一个简单的引导加载程序 并在某些环境中偶然发现了一个问题 在这些环境中 此类指令不起作用 mov si call tbl SI Call table pointer call call tbl Call print c
  • 为什么 GCC 不将 a*a*a*a*a*a 优化为 (a*a*a)*(a*a*a)?

    我正在对科学应用程序进行一些数值优化 我注意到的一件事是 GCC 会优化调用pow a 2 通过将其编译成a a 但是调用pow a 6 没有优化 实际会调用库函数pow 这大大降低了性能 相比之下 英特尔 C 编译器 http en wi
  • Numpy 的舍入方式与 Python 不同

    The code import numpy as np a 5 92270987499999979065 print round a 8 print round np float64 a 8 gives 5 92270987 5 92270
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • AVX-512CD(冲突检测)与原子变量访问有何不同?

    所以我在看他们展示了如何 void Histogram const float age int const hist const int n const float group width const int m const float o
  • Python 相当于 Bit Twiddling Hacks 中的 C 代码?

    我有一个位计数方法 我正在尝试尽可能快地实现 我想尝试下面的算法位摆弄黑客 http graphics stanford edu seander bithacks html CountBitsSetParallel 但我不知道 C 什么是
  • 使用 (float&)int 进行类型双关可以正常工作,(float const&)int 会像 (float)int 一样转换吗?

    VS2019 发布 x86 template
  • 如何在 Linux x86_64 上模拟 iret

    我正在编写一个基于 Intel VT 的调试器 由于当 NMI Exiting 1 时 iret 指令在 vmx guest 中的性能发生了变化 所以我应该自己处理vmx主机中的NMI 否则 guest会出现nmi可重入错误 我查了英特尔手
  • ARMv8 A64 汇编中立即值的范围

    我的理解是 ARMv8 A64 汇编中的立即参数可以是 12 位长 如果是这样的话 为什么这行汇编代码是 AND X12 X10 0xFEF 产生此错误 使用 gcc 编译时 Error immediate out of range at
  • 32 位数字中 1 的数量

    我正在寻找一种在 32 位数字中包含 1 数量的方法 之间不使用循环 任何人都可以帮助我并向我提供代码或算法吗 这样做 提前致谢 See Integer bitCount int http java sun com javase 6 doc
  • 将位图旋转 90 度

    我有一个1 个 64 位整数 我需要在 8 x 8 区域中旋转 90 度 最好使用直接位操作 我想不出任何方便的算法 例如 这个 0xD000000000000000 110100000000000000000000000000000000
  • 如何将 x86 GCC 风格的 C 内联汇编转换为 Rust 内联汇编?

    我在 C 中有以下内联汇编 unsigned long long result asm volatile byte 15 byte 49 shlq 32 rdx orq rdx rax a result rdx return result
  • 如何使用movntdqa避免缓存污染?

    我正在尝试编写一个 memcpy 函数 该函数不会将源内存加载到 CPU 缓存中 目的是避免缓存污染 下面的 memcpy 函数可以工作 但会像标准 memcpy 一样污染缓存 我正在使用带有 Visual C 2008 Express 的
  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • 这种没有推送寄存器的交换有多安全?

    我对汇编非常陌生 下面的代码应该通过两个不同的函数交换两个整数 首先使用swap c然后使用swap asm 但我怀疑 我是否需要push 我的意思是保存 汇编代码之前寄存器的每个值和pop稍后 就在返回之前 main 换句话说 如果我返回
  • GCC的sqrt()编译后如何工作?使用哪种root方法?牛顿-拉夫森?

    只是对标准感到好奇sqrt 来自 GCC 上的 math h 我自己编码的sqrt 使用牛顿拉夫森来做到这一点 是的 我知道 fsqrt 但CPU是如何做到这一点的呢 我无法调试硬件 现代 CPU 中的典型 div sqrt 硬件使用 2
  • 32位PPC rlwinm指令

    我在理解上有点困难rlwinmPPC 汇编指令 旋转左字立即然后与掩码 我正在尝试反转函数的这一部分 rlwinm r3 r3 0 28 28 我已经知道什么了r3 is r3在本例中是一个 4 字节整数 但我不确定这条指令到底是什么rlw

随机推荐