- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在为 6502 cpu 编写一个汇编语言程序,并且发现我需要一个尽可能快的除七例程,特别是可以接受 16 位除数的例程。
我熟悉找到的例程here ,但是推广除七例程发现相当复杂,粗略地考察一下通用算法(使用整数除法)
x/7 ~= (x + x/8 + x/64 ... )/8
表示要处理 16 位范围,可能需要超过 100 个周期才能完成,因为 6502 的单个累加器寄存器以及 6502 上各个内存位移位的相对速度较慢。
我认为查找表可能会有所帮助,但在 6502 上,我当然仅限于 256 字节或更少的查找表。为此,可以假设存在两个 256 字节的查找表 xdiv7 和 xmod7,当使用无符号的单字节值作为表的索引时,可以快速获得字节除以 7 或模的结果分别为 7 个。不过,我不确定如何利用这些来查找完整 16 位范围的值。
同时,我还需要一个模 7 算法,尽管理想情况下,任何可以通过除法得出的解决方案也都会产生模 7 结果。如果需要额外的预计算表,我可以添加这些表,只要所有表的总内存需求不超过大约 3k。
虽然我最终需要一个有符号除法算法,但无符号算法就足够了,因为我可以根据需要将其概括为有符号例程。
任何帮助将不胜感激。
最佳答案
注意:如@Damien_The_Unbeliever评论中指出,upperHigh
和 lowerLow
表是相同的。因此它们可以组合成一个表。然而,这种优化会使代码更难阅读,解释也更难写,因此组合表格留给读者作为练习。
下面的代码展示了如何在将 16 位无符号值除以 7 时生成商和余数。解释代码的最简单方法 (IMO) 是通过一个示例,所以让我们考虑除 0xa732
by 7. 预期结果是:
quotient = 0x17e2
remainder = 4
我们首先将输入视为两个 8 位值,即高
字节和低
字节。 高
字节是0xa7
,低
字节是0x32
。
我们从上
字节计算商和余数:
0xa700 / 7 = 0x17db
0xa700 % 7 = 3
所以我们需要三个表:
upperHigh
存储商的高字节:upperHigh[0xa7] = 0x17
upperLow
存储商的低字节:upperLow[0xa7] = 0xdb
upperRem
存储余数:upperRem[0xa7] = 3
我们从低
字节计算商和余数:
0x32 / 7 = 0x07
0x32 % 7 = 1
所以我们需要两个表:
lowerLow
存储商的低字节:lowerLow[0x32] = 0x07
lowerRem
存储余数:lowerRem[0x32] = 1
现在我们需要汇总最终答案。余数是两个余数之和。由于每个余数都在 [0,6] 范围内,因此总和在 [0,12] 范围内。因此我们可以使用两个 13 字节查找将和转换为最终余数和进位。
商的低字节是该进位与 lowerLow
和 upperLow
表中的值之和。请注意,总和可能会在高字节中生成进位。
商的高字节是该进位与 upperHigh
表中的值之和。
因此,要完成该示例:
remainder = 1 + 3 = 4 // simple add (no carry in)
lowResult = 0x07 + 0xdb = 0xe2 // add with carry from remainder
highResult = 0x17 // add with carry from lowResult
实现此功能的汇编代码由 7 个表查找、一个不带进位的加法指令和两个带进位的加法指令组成。
<小时/>#include <stdio.h>
#include <stdint.h>
uint8_t upperHigh[256]; // index:(upper 8 bits of the number) value:(high 8 bits of the quotient)
uint8_t upperLow[256]; // index:(upper 8 bits of the number) value:(low 8 bits of the quotient)
uint8_t upperRem[256]; // index:(upper 8 bits of the number) value:(remainder when dividing the upper bits by 7)
uint8_t lowerLow[256]; // index:(lower 8 bits of the number) value:(low 8 bits of the quotient)
uint8_t lowerRem[256]; // index:(lower 8 bits of the number) value:(remainder when dividing the lower bits by 7)
uint8_t carryRem[13] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
uint8_t combinedRem[13] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5 };
void populateLookupTables(void)
{
for (uint16_t i = 0; i < 256; i++)
{
uint16_t upper = i << 8;
upperHigh[i] = (upper / 7) >> 8;
upperLow[i] = (upper / 7) & 0xff;
upperRem[i] = upper % 7;
uint16_t lower = i;
lowerLow[i] = lower / 7;
lowerRem[i] = lower % 7;
}
}
void divideBy7(uint8_t upperValue, uint8_t lowerValue, uint8_t *highResult, uint8_t *lowResult, uint8_t *remainder)
{
uint8_t temp = upperRem[upperValue] + lowerRem[lowerValue];
*remainder = combinedRem[temp];
*lowResult = upperLow[upperValue] + lowerLow[lowerValue] + carryRem[temp];
uint8_t carry = (upperLow[upperValue] + lowerLow[lowerValue] + carryRem[temp]) >> 8; // Note this is just the carry flag from the 'lowResult' calcaluation
*highResult = upperHigh[upperValue] + carry;
}
int main(void)
{
populateLookupTables();
uint16_t n = 0;
while (1)
{
uint8_t upper = n >> 8;
uint8_t lower = n & 0xff;
uint16_t quotient1 = n / 7;
uint16_t remainder1 = n % 7;
uint8_t high, low, rem;
divideBy7(upper, lower, &high, &low, &rem);
uint16_t quotient2 = (high << 8) | low;
uint16_t remainder2 = rem;
printf("n=%u q1=%u r1=%u q2=%u r2=%u", n, quotient1, remainder1, quotient2, remainder2);
if (quotient1 != quotient2 || remainder1 != remainder2)
printf(" **** failed ****");
printf("\n");
n++;
if (n == 0)
break;
}
}
关于assembly - 6502 的快速有符号 16 位除以 7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51411251/
你有没有注意到 Excel Vba 代码中除法 2/60 的问题?我正在使用 Excel 2013。请测试以下代码: Sub test1() Dim A As Integer Dim B As Int
我正在运行长时间的模拟。我将结果记录到 vector 中以计算有关数据的统计信息。我意识到,理论上,这些样本可能是除以零的结果。这只是理论上的,我很确定事实并非如此。为了避免修改代码后重新运行模拟,我
我有一些可以包含字母、数字和“#”符号的字符串。 我想删除除以“#”开头的单词以外的数字 下面是一个例子: "table9 dolv5e #10n #dec10 #nov8e 23 hello" 预期
我有以下代码,问题是我尝试将 Double 除以 Int factorial :: Int -> Int factorial 0 = 1 factorial e = e * (factorial e-
我有以下查询,它试图计算出某种产品占产品总数的百分比。 IE:[产品数量]/[产品总数] = 百分比 ;WITH totalCount AS( SELECT CAST(COUN
我正在解析字符串,然后需要将其转换为数字。但如果它包含除以 0 的例子 String str1 = "1+2+3-5/0+4+6" String str2 = "1+2+3-4/0.000 +4+6"
这个问题已经有答案了: Right Shift to Perform Divide by 2 On -1 (6 个回答) 已关闭 9 年前。 在阅读 Collections.reverse 的 Jav
我是 C++ 新手。我听说除以0会导致运行时错误,但是当我尝试时,它抛给我一个编译器错误C2124并且没有创建目标文件,所以编译器会自动运行代码以查看它是否可以在创建之前执行目标文件? (顺便说一句,
我试图在 codefights.com 上解决这个问题,方法是找出最大的质因数并将该数字除以质因数的幂。 int highestPower(int N, int A) { int B =A, j=0,
我对在不同计算机上运行程序有疑问。 我用 C++\windows 7 64 位\Visual Studio 编写了一个程序,该程序在我的计算机上完美运行。 当我尝试在另一台计算机(Windows 7
这个问题已经有答案了: Division in C++ not working as expected (6 个回答) 已关闭 9 年前。 Helo,我是编程新手,遇到了一个问题,我有一个整数,例如
我正在做某事,但遇到了一个我不明白的问题。 double d = 95.24 / (double)100; Console.Write(d); //Break point here 控制台输出是 0.
我需要仅使用按位运算符(例如 ! & ^ ~ 和移位)来计算数字 (a/(2**b)。我得到了以下提示,但我是 C 新手,我不知道什么是代码含义: int bias = x>0 ? 0 : ((1>b
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Java Integer division: How do you produce a double? 当我
嗨,我正在尝试将 numpy 数组分成两部分,并在一个循环中进行此操作,例如: main_array.shape = (50, 400, 400, 3) for i = 0: sub_array_1
这是片段: String myTime = someTime / 1e9d + ","; someTime 是使用 System.nanoTime() 派生的。 1e9d 在这里做什么? 最佳答案 1
Random random = new Random(); int randomx = random.Next(0, 240); 这是我获取随机数的方式,从 0 到 240,如何才能只获取除以 5 的
我一直在处理一个应用程序,因为图像表现得很奇怪,所以我决定打开 Wall 标志,看看是否有任何奇怪的事情发生。它揭示了一个新的警告: character.cpp(364): warning C4723
我是 Android Studio 的新手,我正在开发一个计算器应用程序。现在,当我除以零时,自然会收到错误消息“Infinity”,但如果我想将其更改为“不能除以零”,我该怎么做呢? impor
如何显示每 5 日创建一个新行的表中的数据 ? 例子 data: [1,2,3,4,5,6]; 成分: {{item}} 预期的: | 1 | 2 | 3 | 4 | 5 | | 6 |
我是一名优秀的程序员,十分优秀!