mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-22 13:31:21 +03:00
2fd92f280d
* added Conversion/decimal_to_anybase.c * Added Converstions/decimal_to_any_base.c * Enhencement of decimal_to_any_base.c * Update conversions/decimal_to_any_base.c Co-authored-by: David Leal <halfpacho@gmail.com> * Update conversions/decimal_to_any_base.c Co-authored-by: David Leal <halfpacho@gmail.com> * updating DIRECTORY.md * Update conversions/decimal_to_any_base.c Co-authored-by: David Leal <halfpacho@gmail.com> * Update conversions/decimal_to_any_base.c Co-authored-by: David Leal <halfpacho@gmail.com> * text enhencement and debugging * comments norming * builtin int types declacration changed into arch optimized int types * comments norming * Adding booleans and int types normalization * Translation of the program into a function and tests added * Commentary rewriting in decimal_to_anybase and code beautify * added 1 comments in main and code beautify * Commentary norming * Code norming * Apply suggestions from code review Co-authored-by: Votre Nom <Vous@exemple.com> Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
170 lines
4.2 KiB
C
170 lines
4.2 KiB
C
/**
|
|
* @file
|
|
* @author [jucollet972](https://github.com/jucollet972)
|
|
* @brief [Decimal to any-base](http://codeofthedamned.com/index.php/number-base-conversion) is a C function wich convert positive decimal
|
|
* integer to any positive ascii base with the base's alphabet given in input and return it in a dynamically allocated string(recursive way)
|
|
*/
|
|
|
|
#include <stdio.h> /// for IO operations
|
|
#include <string.h> /// for strchr and strlen
|
|
#include <stdint.h> /// for CPU arch's optimized int types
|
|
#include <stdbool.h> /// for boolean types
|
|
#include <assert.h> /// for assert
|
|
#include <stdlib.h> /// for malloc and free
|
|
|
|
/**
|
|
* @brief Checking if alphabet is valid
|
|
* @param base alphabet inputed by user
|
|
* @return int64_t as success or not
|
|
*/
|
|
bool isbad_alphabet(const char* alphabet) {
|
|
uint64_t len = strlen(alphabet);
|
|
|
|
/* Checking th lenght */
|
|
if (len < 2) {
|
|
return true;
|
|
}
|
|
/* Browse the alphabet */
|
|
for (int i = 0; i < len ; i++) {
|
|
/* Searching for duplicates */
|
|
if (strchr(alphabet + i + 1, alphabet[i]))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate the final length of the converted number
|
|
* @param nb to convert
|
|
* @param base calculated from alphabet
|
|
* @return Converted nb string length
|
|
*/
|
|
uint64_t converted_len(uint64_t nb, short base) {
|
|
/* Counting the number of characters translated to the base*/
|
|
if (nb > base - 1) {
|
|
return (converted_len(nb/base, base) + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* @brief Convert positive decimal integer into anybase recursively
|
|
* @param nb to convert
|
|
* @param alphabet inputed by user used for base convertion
|
|
* @param base calculated from alphabet
|
|
* @param converted string filled with the convertion's result
|
|
* @return void
|
|
*/
|
|
void convertion(uint64_t nb, const char* alphabet, short base, char* converted) {
|
|
/* Recursive convertion */
|
|
*(converted) = *(alphabet + nb%base);
|
|
if (nb > base - 1) {
|
|
convertion(nb/base, alphabet, base, --converted);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief decimal_to_anybase ensure the validity of the parameters and convert any unsigned integers into any ascii positive base
|
|
* @param nb to convert
|
|
* @param base's alphabet
|
|
* @returns nb converted on success
|
|
* @returns NULL on error
|
|
*/
|
|
char* decimal_to_anybase(uint64_t nb, const char* alphabet) {
|
|
char* converted;
|
|
|
|
/* Verify that alphabet is valid */
|
|
if (isbad_alphabet(alphabet)) {
|
|
return NULL;
|
|
}
|
|
/* Convertion */
|
|
uint64_t base = strlen(alphabet);
|
|
uint64_t final_len = converted_len(nb, base);
|
|
converted = malloc(sizeof(char) * (final_len + 1));
|
|
converted[final_len] = 0;
|
|
convertion(nb, alphabet, base, converted + final_len - 1);
|
|
return converted;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Self-test implementations
|
|
* @returns void
|
|
*/
|
|
static void test()
|
|
{
|
|
char* ret = NULL;
|
|
char* reference = NULL;
|
|
|
|
/* min dec*/
|
|
reference = "0";
|
|
ret = decimal_to_anybase(0, "0123456789");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
|
|
/* max dec*/
|
|
reference = "18446744073709551615";
|
|
ret = decimal_to_anybase(18446744073709551615, "0123456789");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
|
|
/* negative dec*/
|
|
reference = "18446744073709551615";
|
|
ret = decimal_to_anybase(-1, "0123456789");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
|
|
/* bin */
|
|
reference = "101010";
|
|
ret = decimal_to_anybase(42, "01");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
|
|
/* octal */
|
|
reference = "52";
|
|
ret = decimal_to_anybase(42, "01234567");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
|
|
/* hexa */
|
|
reference = "2A";
|
|
ret = decimal_to_anybase(42, "0123456789ABCDEF");
|
|
for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) {
|
|
assert(ret[i] == reference[i]);
|
|
}
|
|
if (ret != NULL) {
|
|
free(ret);
|
|
}
|
|
printf("[+] All tests have successfully passed!\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Main function
|
|
* @returns 0 on exit
|
|
*/
|
|
int main()
|
|
{
|
|
test(); // run self-test implementations
|
|
return 0;
|
|
}
|