Could you please advise if there is any effective way to calculate sum of two numbers in hex without conversion them to base10? I know how to calculate sum manually (actually the same as in the base10), but maybe there is more effective way? I am going to implement the algorithm in ABAP which is able to calculate sum of hex maximum 4 bytes length.
-
"sum of hex strings" does not make any sense to me. What are you trying to do? – vwegert Feb 16 '16 at 08:50
-
I am sorry, just want to calculate sum of numbers in base16 without conversion to base10 – user1500581 Feb 16 '16 at 08:51
-
What do you mean under "effective way"? What is "unlimited HEX string"? String with indefinite length? – Suncatcher Feb 16 '16 at 09:02
-
2Summing things is always a measure, never a goal. What do you want to achieve in the end? It's very likely you're using the wrong approach for whatever you're trying to do. – vwegert Feb 16 '16 at 09:04
-
Effective way - something faster and native for computers then school algorithm for manual base16 numbers sum calculation. "unlimited HEX string" - I meant any numbers in base16 (8 byte number in hex + 1 byte number in hex, 16 byte number in hex + 8 byte number in hex). – user1500581 Feb 16 '16 at 09:08
-
Would like to find something faster then http://mathforum.org/library/drmath/view/66714.html – user1500581 Feb 16 '16 at 09:23
-
1What do You have so far? – icbytes Feb 16 '16 at 10:08
-
If you are looking for a native solution as you wrote, then ABAP is surely a wrong choice for doing it. – Jagger Feb 16 '16 at 10:16
-
There was someone asking a similar question in here, i think, and someone answered, that ABAP is not really the proper language to do such calculations, ABAP's main focus is business logic, this does not mean, that they do not have such functions, but they are mainly kernel-calls to c-binaries. – icbytes Feb 16 '16 at 10:17
-
@icbytes Yes, I did it [here](http://stackoverflow.com/questions/35316043/abap-find-out-all-program-screens#comment58351699_35316043). Best regards. – Nelson Miranda Feb 16 '16 at 17:58
-
4I think the confusion here stems from the fact that numbers are not "base xx" at all. The string representations of numbers can be "base xx" or "base yy", but not the numbers themselves. Adding two numbers is always the same, and "base" does not matter, unless you try to add the string representations. – Rudy Velthuis Feb 17 '16 at 07:28
3 Answers
Disclaimer: I don't know ABAP, so I might be completely off in some points.
Summing is essentially a trade-off between the complexity of adding two digits and the number of digits. At the hardware level, numbers are represented in binary, so each digit addition is fairly easy, but there are many of them. When you do arbitrary size (or big integer) arithmetic, you usually avoid implementing these bit-level operations in software, but instead group a larger number of bits together into a single logical digit. If you group 4 bits together, you end up with long addition in hexadecimal.
But you can form even larger digits, by combining multiple hexadecimal digits into a single number. If your machine allows for no more than 4 bytes per number, then I'd take half that number, i.e. 2 bytes or 16 bits per digit. So you take groups of four hexadecimal digits, combine them into a number (which would get represented in base 10, but since you just compute with it, not print it, it's base 2 internally, at least in the languages I know) and perform the addition on those. The result of adding two 16-bit numbers will have 17 bit. Of these, the least significant 16 form a digit of the result, while the most significant one is the carry for the next position. When turning the resulting numbers back into hexadecimal strings, make sure that each number gets zero-padded to 4 hex digits before you concatenate them again.
Some architectures have a carry flag, so they can take the full register width (4 bytes in your case) as a single digit, and still know whether to add a carry to the next position. But accessing that from high-level languages tends to be tedious, which is why I suggest you use half the register width.
Note that the digit grouping, padding and concatenation will make the code considerably more complex than if you were to add each digit by itself. You'll have to evaluate whether the performance gain actually warrants the added complexity.

- 57,380
- 22
- 148
- 276
Summing two number base 16 represented with the digits 0123456789ABCDEF is no different than summing the usual base-10 representation, except of course the summing table is different. As usual, you need to carry as may be necessary. The summing table is a symmetric matrix, for which this is the upper representation (no ABAP here, sorry! I hope you can read Kotlin)
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')),
)
Sum is commutative; the sum of, say, 'A' and '7' is at the intersection of the same row/col above, in this case Pair(CARRY,'1')
namely '1' and there is a carry. This is the core of a possible implementation in 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]
}
}
To sum two multiple digit numbers, the algorithm is intuitively immediate and is O(n) in the number of digits: just sum each digit from the least significant to the most significant, remembering the carry. Implementation is, as usual, fraught with the additional complication of the details. This is the core of a possible implementation in 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()
}
}
}
}
}

- 21
- 2
Simply use variables of type X, as in the below example:
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.
Without changing the input parameters this will output:
BAFF + 1234 = CD33

- 2,510
- 1
- 17
- 18