您能否告知是否有任何有效的方法来计算十六进制中两个数字的总和而无需将它们转换为 base10?我知道如何手动计算总和(实际上与 base10 中的相同(,但也许有更有效的方法?我将在ABAP中实现该算法,该算法能够计算十六进制最大4字节长度的总和。
免责声明:我不知道ABAP,所以我可能在某些方面完全不对劲。
求和本质上是两位数相加的复杂性和位数之间的权衡。在硬件级别,数字以二进制表示,因此每个数字相加都相当容易,但其中有很多。当您进行任意大小(或大整数(算术时,通常避免在软件中实现这些位级运算,而是将大量位组合成单个逻辑数字。如果将 4 位组合在一起,最终会得到十六进制的长加法。
但是,通过将多个十六进制数字组合成一个数字,您可以形成更大的数字。如果您的机器允许每个数字不超过 4 个字节,那么我会取一半的数字,即每个数字 2 个字节或 16 位。因此,您将四个十六进制数字分组,将它们组合成一个数字(该数字将以 10 为基数表示,但由于您只是使用它进行计算,而不是打印它,因此它在内部是 2 进制,至少在我知道的语言中(并对这些数字执行加法。将两个 16 位数字相加的结果将具有 17 位。其中,最不重要的 16 个构成结果的数字,而最重要的一个是下一个位置的进位。将生成的数字重新转换为十六进制字符串时,请确保每个数字都以零填充为 4 个十六进制数字,然后再将它们连接起来。
某些体系结构具有进位标志,因此它们可以将完整的寄存器宽度(在您的情况下为 4 字节(作为个位数,并且仍然知道是否将进位添加到下一个位置。但是从高级语言访问它往往很乏味,这就是为什么我建议你使用一半的寄存器宽度。
请注意,数字分组、填充和串联将使代码比单独添加每个数字要复杂得多。您必须评估性能提升是否真的保证了增加的复杂性。
数字 0123456789ABCDEF 表示的两个以 16 为底的数字求和与通常的以 10 为底表示表示数求和没有什么不同,当然求和表不同。 像往常一样,您需要根据需要携带。 求和表是一个对称矩阵,这是上层表示(这里没有ABAP,对不起! 我希望你能读懂科特林(
private const val CARRY = '1'
private val ST = arrayOf( // summation table base 16
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ arrayOf(Pair(null,'0'),Pair(null,'1'),Pair(null,'2'),Pair(null,'3'),Pair(null,'4'),Pair(null,'5'),Pair(null,'6'),Pair(null,'7'),Pair(null,'8'), Pair(null,'9'),Pair(null,'A'), Pair(null,'B'), Pair(null,'C'), Pair(null,'D'), Pair(null,'E'), Pair(null,'F')),
/* 1 */ arrayOf( Pair(null,'2'),Pair(null,'3'),Pair(null,'4'),Pair(null,'5'),Pair(null,'6'),Pair(null,'7'),Pair(null,'8'),Pair(null, '9'), Pair(null,'A'),Pair(null,'B'), Pair(null,'C'), Pair(null,'D'), Pair(null,'E'), Pair(null,'F'), Pair(CARRY,'0')),
/* 2 */ arrayOf( Pair(null,'4'),Pair(null,'5'),Pair(null,'6'),Pair(null,'7'),Pair(null,'8'),Pair(null,'9'),Pair(null, 'A'), Pair(null,'B'),Pair(null,'C'), Pair(null,'D'), Pair(null,'E'), Pair(null,'F'), Pair(CARRY,'0'),Pair(CARRY,'1')),
/* 3 */ arrayOf( Pair(null,'6'),Pair(null,'7'),Pair(null,'8'),Pair(null,'9'),Pair(null,'A'),Pair(null, 'B'), Pair(null,'C'),Pair(null,'D'), Pair(null,'E'), Pair(null,'F'), Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2')),
/* 4 */ arrayOf( Pair(null,'8'),Pair(null,'9'),Pair(null,'A'),Pair(null,'B'),Pair(null, 'C'), Pair(null,'D'),Pair(null,'E'), Pair(null,'F'), Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2'),Pair(CARRY,'3')),
/* 5 */ arrayOf( Pair(null,'A'),Pair(null,'B'),Pair(null,'C'),Pair(null, 'D'), Pair(null,'E'),Pair(null,'F'), Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2'),Pair(CARRY,'3'),Pair(CARRY,'4')),
/* 6 */ arrayOf( Pair(null,'C'),Pair(null,'D'),Pair(null, 'E'), Pair(null,'F'),Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2'),Pair(CARRY,'3'),Pair(CARRY,'4'),Pair(CARRY,'5')),
/* 7 */ arrayOf( Pair(null,'E'),Pair(null, 'F'),Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2'),Pair(CARRY,'3'),Pair(CARRY,'4'),Pair(CARRY,'5'),Pair(CARRY,'6')),
/* 8 */ arrayOf( Pair(CARRY,'0'),Pair(CARRY,'1'),Pair(CARRY,'2'),Pair(CARRY,'3'),Pair(CARRY,'4'),Pair(CARRY,'5'),Pair(CARRY,'6'),Pair(CARRY,'7')),
/* 9 */ arrayOf( Pair(CARRY,'2'),Pair(CARRY,'3'),Pair(CARRY,'4'),Pair(CARRY,'5'),Pair(CARRY,'6'),Pair(CARRY,'7'),Pair(CARRY,'8')),
/* A */ arrayOf( Pair(CARRY,'4'),Pair(CARRY,'5'),Pair(CARRY,'6'),Pair(CARRY,'7'),Pair(CARRY,'8'),Pair(CARRY,'9')),
/* B */ arrayOf( Pair(CARRY,'6'),Pair(CARRY,'7'),Pair(CARRY,'8'),Pair(CARRY,'9'),Pair(CARRY,'A')),
/* C */ arrayOf( Pair(CARRY,'8'),Pair(CARRY,'9'),Pair(CARRY,'A'),Pair(CARRY,'B')),
/* D */ arrayOf( Pair(CARRY,'A'),Pair(CARRY,'B'),Pair(CARRY,'C')),
/* E */ arrayOf( Pair(CARRY,'C'),Pair(CARRY,'D')),
/* F */ arrayOf( Pair(CARRY,'E')),
)
总和是可交换的;例如,"A"和"7"的总和位于上面同一行/列的交点处,在这种情况下Pair(CARRY,'1')
即"1"并且有一个进位。 这是 Kotlin 中可能实现的核心:
fun hexCharSum(a: Char, b: Char): Pair<Char?, Char> {
check(a in hexSymbolSet && b in hexSymbolSet) { "$a, $b should be in $hexSymbolSet" }
val i = a.hex2dec()
val j = b.hex2dec()
return when {
i < j -> ST[i][j-i]
j < i -> ST[j][i-j]
else -> ST[i][0]
}
}
为了对两个多位数的数字求和,该算法直观地立即在位数上为 O(n(:只需将每个数字从最不重要到最重要求和,记住进位。 像往常一样,实施充满了细节的额外复杂性。这是 Kotlin 中可能实现的核心:
fun hexStringSum(a: String, b: String): String {
check(regex09AF.matches(a) && regex09AF.matches(b)) { "$a, $b must be unsigned hexadecimal numbers" }
val al = a.length
val bl = b.length
fun zipAssemble(zipLength: Int, ar: String, br: String, sb: StringBuilder): Pair<Char?, StringBuilder> {
var lastCarry: Char? = null
for (ix in (0 until zipLength)) {
val aux = hexCharSum(ar[ix], br[ix])
val res = if (0 == ix) aux else lastCarry?.let { lastCy ->
aux.first?.let {
/* keep track of aux's known carry */ Pair(aux.first, hexCharSum(aux.second, lastCy).second)
} ?: hexCharSum(aux.second, lastCy)
} ?: aux
lastCarry = res.first
sb.append(res.second)
}
return Pair(lastCarry, sb)
}
fun complete(startIx: Int, endIx: Int, srcr: String, sb: StringBuilder, lastCarry: Char?): StringBuilder {
var thisCarry: Char? = lastCarry
for (ix in (startIx until endIx)) {
val res = thisCarry?.let {
hexCharSum(srcr[ix], it)
} ?: Pair(null, srcr[ix])
thisCarry = res.first
sb.append(res.second)
}
return thisCarry?.let { sb.append(CARRY) } ?: sb
}
return when {
0 == al -> b
0 == bl -> a
else -> {
val ar = a.reversed()
val br = b.reversed()
val sb = StringBuilder()
when {
al < bl -> {
val (lastCarry, sbAlias) = zipAssemble(al, ar, br, sb)
complete(al, bl, br.uppercase(), sbAlias, lastCarry).reverse().toString()
}
bl < al -> {
val (lastCarry, sbAlias) = zipAssemble(bl, ar, br, sb)
complete(bl, al, ar.uppercase(), sbAlias, lastCarry).reverse().toString()
}
else -> {
val (lastCarry, sbAlias) = zipAssemble(al, ar, br, sb)
lastCarry?.let { sbAlias.append(CARRY) }
sbAlias.reverse().toString()
}
}
}
}
}
只需使用 X 类型的变量,如下例所示:
REPORT Y_HEX_SUM.
PARAMETERS: p_h1(4) type c DEFAULT 'BAFF',
p_h2(4) type c DEFAULT '1234'.
data: g_h1(2) type x, " This works in Unicode systems, otherwise make length 4.
g_h2(2) type x,
g_sum(2) type x.
START-OF-SELECTION.
g_h1 = p_h1.
g_h2 = p_h2.
g_sum = g_h1 + g_h2.
write: / g_h1, '+', g_h2, '=', g_sum.
在不更改输入参数的情况下,这将输出:
BAFF + 1234 = CD33