initial
This commit is contained in:
7
Makefile
Normal file
7
Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
LIBFILES=nibble.c
|
||||
TESTFILES=$(wildcard tests/*.c)
|
||||
|
||||
test:
|
||||
gcc $(LIBFILES) $(TESTFILES) -o test_bcd
|
||||
./test_bcd
|
||||
rm test_bcd
|
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# nibbles
|
||||
|
||||
A toy C library that converts numbers to and from [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal).
|
||||
I suggest you don't use it.
|
||||
|
||||
## Installation
|
||||
|
||||
Don't. The makefile only includes a test target, because I want to test my code.
|
||||
|
||||
## Usage
|
||||
|
||||
The library knows how to convert `uint<n>_t` types into BCD. It also knows
|
||||
how to convert them back into `uint64_t`—only that because any other
|
||||
representation might lead to a loss of information. It can also convert from
|
||||
BCD to strings. The functions are:
|
||||
|
||||
```c
|
||||
bcd bcd_zeros(); // creates a BCD of value 0
|
||||
|
||||
bcd bcd_from_8(uint8_t); // creates a BCD from a byte
|
||||
bcd bcd_from_16(uint16_t); // creates a BCD from 2 bytes
|
||||
bcd bcd_from_32(uint32_t); // and so on
|
||||
bcd bcd_from_64(uint64_t); // ..
|
||||
|
||||
uint8_t bcd_digits(bcd); // gets the number of digits in the BCD
|
||||
uint64_t bcd_to_64(bcd); // converts a BCD to a 8 bytes (64 bit) number
|
||||
char* bcd_to_string(bcd); // converts a BCD to a string (memory is now yours)
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
<hr/>
|
||||
|
||||
Have fun!
|
77
nibble.c
Normal file
77
nibble.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "nibble.h"
|
||||
#include <stdio.h>
|
||||
|
||||
bcd bcd_zeros() {
|
||||
bcd bcd;
|
||||
memset(bcd.internal, 0, sizeof(bcd.internal));
|
||||
return bcd;
|
||||
}
|
||||
|
||||
#define bcd_from_n(X) {\
|
||||
int i;\
|
||||
bcd res = bcd_zeros();\
|
||||
for (i = 9; i >= 0; --i) {\
|
||||
if (!X) break;\
|
||||
res.internal[i] = (X % 10);\
|
||||
X /= 10;\
|
||||
if (!X) break;\
|
||||
res.internal[i] += (X % 10) << 4;\
|
||||
X /= 10;\
|
||||
}\
|
||||
return res;\
|
||||
}
|
||||
|
||||
bcd bcd_from_8(uint8_t x) {
|
||||
bcd_from_n(x);
|
||||
}
|
||||
|
||||
bcd bcd_from_16(uint16_t x) {
|
||||
bcd_from_n(x);
|
||||
}
|
||||
|
||||
bcd bcd_from_32(uint32_t x) {
|
||||
bcd_from_n(x);
|
||||
}
|
||||
|
||||
bcd bcd_from_64(uint64_t x) {
|
||||
bcd_from_n(x);
|
||||
}
|
||||
|
||||
uint8_t bcd_digits(bcd x) {
|
||||
int i;
|
||||
for (i = 0; i < 20; i+=2) {
|
||||
if (x.internal[i/2] != 0) {
|
||||
if (!(x.internal[i/2]&0xf0)) i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 20-i;
|
||||
}
|
||||
|
||||
uint64_t bcd_to_64(bcd x) {
|
||||
int i;
|
||||
uint64_t res = 0;
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
res *= 100;
|
||||
res += ((x.internal[i] & 0xf0) >> 4) * 10;
|
||||
res += (x.internal[i] & 0xf);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char* bcd_to_string(bcd x) {
|
||||
int i = 0;
|
||||
uint8_t n = bcd_digits(x);
|
||||
int to = 10-(n+1)/2;
|
||||
char* res = malloc(n+1);
|
||||
|
||||
for (i = 0; i < n; i+=2, to++) {
|
||||
res[i] = ((x.internal[to] & 0xf0) >> 4) + '0';
|
||||
res[i+1] = (x.internal[to] & 0xf) + '0';
|
||||
}
|
||||
|
||||
res[n] = '\0';
|
||||
return res;
|
||||
}
|
15
nibble.h
Normal file
15
nibble.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// struct for sizeof info
|
||||
typedef struct { short internal[10]; } bcd;
|
||||
|
||||
bcd bcd_zeros();
|
||||
bcd bcd_from_8(uint8_t);
|
||||
bcd bcd_from_16(uint16_t);
|
||||
bcd bcd_from_32(uint32_t);
|
||||
bcd bcd_from_64(uint64_t);
|
||||
uint8_t bcd_digits(bcd);
|
||||
uint64_t bcd_to_64(bcd);
|
||||
char* bcd_to_string(bcd);
|
1040
tests/greatest.h
Normal file
1040
tests/greatest.h
Normal file
File diff suppressed because it is too large
Load Diff
103
tests/test.c
Normal file
103
tests/test.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "greatest.h"
|
||||
#include "../nibble.h"
|
||||
|
||||
TEST bcd_zeros_is_zero() {
|
||||
bcd x = bcd_zeros();
|
||||
|
||||
for (int i = 0; i < 10; i++) ASSERT_EQ_FMT(0, x.internal[i], "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_zeros_length_zero() {
|
||||
bcd x = bcd_zeros();
|
||||
|
||||
ASSERT_EQ_FMT(0, bcd_digits(x), "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_8_length_3() {
|
||||
bcd x = bcd_from_8(((uint8_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(3, bcd_digits(x), "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_16_length_5() {
|
||||
bcd x = bcd_from_16(((uint16_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(5, bcd_digits(x), "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_32_length_10() {
|
||||
bcd x = bcd_from_32(((uint32_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(10, bcd_digits(x), "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_64_length_20() {
|
||||
bcd x = bcd_from_64(((uint64_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(20, bcd_digits(x), "%d");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_8_and_back() {
|
||||
bcd x = bcd_from_8(((uint8_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(255llu, bcd_to_64(x), "%llu");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_16_and_back() {
|
||||
bcd x = bcd_from_16(((uint16_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(65535llu, bcd_to_64(x), "%llu");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_32_and_back() {
|
||||
bcd x = bcd_from_32(((uint32_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(4294967295llu, bcd_to_64(x), "%llu");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_64_and_back() {
|
||||
bcd x = bcd_from_64(((uint64_t)0)-1);
|
||||
|
||||
ASSERT_EQ_FMT(18446744073709551615llu, bcd_to_64(x), "%llu");
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST bcd_string() {
|
||||
bcd x = bcd_from_64(((uint64_t)0)-1);
|
||||
|
||||
ASSERT_STR_EQ("18446744073709551615", bcd_to_string(x));
|
||||
PASS();
|
||||
}
|
||||
|
||||
SUITE(tests) {
|
||||
RUN_TEST(bcd_zeros_is_zero);
|
||||
RUN_TEST(bcd_zeros_length_zero);
|
||||
RUN_TEST(bcd_8_length_3);
|
||||
RUN_TEST(bcd_16_length_5);
|
||||
RUN_TEST(bcd_32_length_10);
|
||||
RUN_TEST(bcd_64_length_20);
|
||||
RUN_TEST(bcd_8_and_back);
|
||||
RUN_TEST(bcd_16_and_back);
|
||||
RUN_TEST(bcd_32_and_back);
|
||||
RUN_TEST(bcd_64_and_back);
|
||||
RUN_TEST(bcd_string);
|
||||
}
|
||||
|
||||
GREATEST_MAIN_DEFS();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
GREATEST_MAIN_BEGIN();
|
||||
|
||||
RUN_SUITE(tests);
|
||||
|
||||
GREATEST_MAIN_END();
|
||||
}
|
Reference in New Issue
Block a user