Is there any methods to encode and decode CRC using natural numbers? - crc

I know how to encode and decode CRC. For example given the binary message to be encoded was 11010011101100 and the genrator polynomial is 1011
Then the result is:
11010011101100 000 <--- input left padded by 3 bits
`1011` <--- divisor
01100011101100 000 <--- result
1011 <--- divisor ...
00111011101100 000
1011
...
-----------------
00000000000000 100 <---remainder (3 bits)
and to decode it you use the same technique however replace the 3 zeros with the remainder (100)
however is there a way of using this same method to encode and decode crc codes using normal natural numbers without converting them to binary?
I tried to do some research however, I cant find any method or examples to do it using natural numbers I only seem to find binary examples. Any help please guys?

It's the same exact algorithm. You are working with natural numbers. The way they're written is immaterial. "Shift left by three bits" is equivalent to "multiply by 8". "Shift right by one bit" is equivalent to "divide by two, discarding the remainder". "Take the last three bits" is equivalent to "take the remainder from dividing by 8". The bit-xor of two numbers isn't very easy to describe in arithmetical terms though.

Related

CRC checksum calculation algorithm

Can anyone with good knowledge of CRC calculation verify that this code
https://github.com/psvanstrom/esphome-p1reader/blob/main/p1reader.h#L120
is actually calculating crc according to this description?
CRC is a CRC16 value calculated over the preceding characters in the data message (from
“/” to “!” using the polynomial: x16+x15+x2
+1). CRC16 uses no XOR in, no XOR out and is
computed with least significant bit first. The value is represented as 4 hexadecimal characters (MSB first).
There's nothing in the linked code about where it starts and ends, and how the result is eventually represented, but yes, that code implements that specification.

Why does this two's complement shortcut work?

A shortcut method of forming the two's complement of a binary number is to copy bits from the right until a one-bit has been copied, then complement (invert) the remaining bits.
That's explained on SO here and also on Wikipedia.
What is not explained is why this shortcut works, that is, why does it produce the same result as inverting all the bits and adding one. So, my question is, why does this work?
It works because adding one to a binary number is accomplished by flipping all 1s to 0s from the right until a 0 is reached, flip that to 1 and stop (essentially carrying the overflow of adding 1 to 1).
So one method flips only the bits to the left of the first one, while the other flips all bits, then flips the first 1 (now 0) and the bits to the right of it back.
e.g.:
01000100
10111100 // copy bits until a 1 is reached, then flip the rest
vs
01000100
10111011 // invert all bits:
+ 1 // add one
10111100
Write the number as x10k (some string of bits followed by a 1 and then k zeroes).
Suppose you complement it and then add one, you'd get first y01k (where y is the complement of x), then the increment carries through the trailing ones and flips the zero back on, to y10k.
Which is the same thing as just complementing x and leaving the tail alone.
So I've found a shortcut;
Note:This trick works if you are allowed to use a calculator with binary to decimal conversion available.
If there was an MCQ question like;
Q)The 8bit 2's complement representation of 5 is ....
,Use the formula = 2^(number of bits) - the number
In this case its 8 bits and the number 5
So; (2^8) - 5
2^8=256
256-5= 251
Convert 251 into binary using calculator
Then = 11111011 in binary.
Works with any number with respect to number of bits.

How to inverse a number without using array or any arithmetic operations

How can I reverse a number without using arrays or any arithmetic operations i.e from 85 to 58. Using bitwise operators might be the solution. But what series of operations are needed to reverse a number. I've tried shifting and complementing.
And is there a way to get binary or hexadecimal as input and perform operations on it. Rather than getting int and typecast at printf?
there are alot of api's to do that // but the easiest way use a stack :D or convert it to string then it will be such as array you can inverse it easilly
I found the answer after all. Using the right shift 8 times and left shift 2 times would work on a 2 digit number. And follow the shift bits for different digit numbers,

What exactly means U0.8, U4.8, U12.8, S0.4, S4.4, S12.4, U8.8 etc. fixed-point representation?

I'm finding it hard to understand fixed-point representations. When I have unsigned type of data (C++) and I want to work with that number as if it is fixed-point, I need do do certain amount of bit manipulation which aren't clear to me.
So let's say I want that my number which is unsigned and can be max 255 (8 bit number) be represented in U4.4 or U12.8 or S13.8 or whichever notation (U - unsigned, S - signed, and it comes in question when my number is int). Basically I'm expanding (or I hope that I'm) the number, working on it, and then returning it to the previous state.
How do I do that?
Can someone share link where I can find something closely related to this subject. I was looking for three hours and all I have found are general explanations on fixed-point arithmetics, nothing very practical.
Thanks
It's telling you how many bits are used for each side of the decimal point.
Take a simple example. 2 bytes, 16 bits.
That can easily be U8.8. That is, the top byte is the "integer" part, and the low byte in the "fraction" part.
So, let's make this a bit easier as an explanation.
Consider binary coded decimal. That's where you encode decimal numbers in to nibbles of bytes, each byte is 2 digits. Each nibble is a decimal digit, so 1001 0010 is "92". With two bytes, 1001 0010 0100 0111 is 9287.
So, you can see how, with no fractions, 16 bits can represent 0000 to 9999. Using you notation, that could be U16.0.
Now, you can see if we logically put the decimal point in the middle, now we can have 00.00 to 99.99, or U8.8.
The underlying bit pattern is the same, it's all a matter where you logically put the decimal point.
Now, in this example, you saw the decimal point between decimal digits.
If you're using a binary representation, then the "decimal" point is between binary digits.
So, U8.8 us 11111111. 11111111, a U12.4 is 11111111 1111.1111.
The S vs U tells you about the Sign bit. So, instead of U8.8 you'd have S7.8 S1111111. 11111111.
When you have numbers that are represented similarly, then it's just binary math upon then, just like any other number (like an integer). It's when you convert the number to ascii, or combine then with other representations that you need to shift about.
For example. To add a U8.8 to a U12.4, you need to convert the U8.8 to U12.4 before performing your math.
So, 11111111. 11111111 would just need to be shifted right 4 places to become 00001111 1111.1111. Then you can work on the two 12.4 numbers like normal. You'll notice that you lose precision of the 8.8 number during the conversion. This is known as "tough luck". You could also elevate both numbers to a higher representation, there's all sorts of options.

I don't get Golomb / Rice coding: It does make more bits of the input, or does it?

Or, maybe, what I don't get is unary coding:
In Golomb, or Rice, coding, you split a number N into two parts by dividing it by another number M and then code the integer result of that division in unary and the remainder in binary.
In the Wikipedia example, they use 42 as N and 10 as M, so we end up with a quotient q of 4 (in unary: 1110) and a remainder r of 2 (in binary 010), so that the resulting message is 1110,010, or 8 bits (the comma can be skipped). The simple binary representation of 42 is 101010, or 6 bits.
To me, this seems due to the unary representation of q which always has to be more bits than binary.
Clearly, I'm missing some important point here. What is it?
The important point is that Golomb codes are not meant to be shorter than the shortest binary encoding for one particular number. Rather, by providing a specific kind of variable-length encoding, they reduce the average length per encoded value compared to fixed-width encoding, if the encoded values are from a large range, but the most common values are generally small (and hence are using only a small fraction of that range most of the time).
As an example, if you were to transmit integers in the range from 0 to 1000, but a large majority of the actual values were in the range between 0 and 10, in a fixed-width encoding, most of the transmitted codes would have leading 0s that contain no information:
To cover all values between 0 and 1000, you need a 10-bit wide encoding in fixed-width binary. Now, as most of your values would be below 10, at least the first 6 bits of most numbers would be 0 and would carry little information.
To rectify this with Golomb codes, you split the numbers by dividing them by 10 and encoding the quotient and the remainder separately. For most values, all that would have to be transmitted is the remainder which can be encoded using 4 bits at most (if you use truncated binary for the remainder it can be less). The quotient is then transmitted in unary, which encodes as a single 0 bit for all values below 10, as 10 for 10..19, 110 for 20..29 etc.
Now, for most of your values, you have reduced the message size to 5 bits max, but you are still able to transmit all values unambigously without separators.
This comes at a rather high cost for the larger values (for example, values in the range 990..999 need 100 bits for the quotient), which is why the coding is optimal for 2-sided geometric distributions.
The long runs of 1 bits in the quotients of larger values can be addressed with subsequent run-length encoding. However, if the quotients consume too much space in the resulting message, this could indicate that other codes might be more appropriate than Golomb/Rice.
One difference between the Golomb coding and binary code is that binary code is not a prefix code, which is a no-go for coding strings of arbitrarily large numbers (you cannot decide if 1010101010101010 is a concatenation of 10101010 and 10101010 or something else). Hence, they are not that easily comparable.
Second, the Golomb code is optimal for geometric distribution, in this case with parameter 2^(-1/10). The probability of 42 is some 0.3 %, so you get the idea about how important is this for the length of the output string.