I wanted to build a C program to convert any number to Indian Currency Format. It can take inputs with negative sign, leading zeros and Decimal point + Mantissa and it will format the input to take care of the leading zeros and add the commas according to Indian number format. For example, numbers in Indian Number Format are represented as:
Minus sign: "-12345" -> "-12,345"
Decimal Point: "-12345.123" -> "-12,345.123"
Leading Zero's: 000000.123 → "0.123" or "-000123456.1234" -> "-1,23,456.1234"
I would like to optimise this code in terms of time and space complexity, make it more concise and clean if possible.
The basic logic of adding the commas is to first copy the sign character if it exists to the second array and then remove it from the original number array. Then if the number of digits in the Exponent part is odd then 1 digit is copied to the second array and removed to make the length even. then for every odd value of the index 'i' a comma is added.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *convertToInrFormat(char *lp_number, int lv_l)
{
char *lp_fnumber = '\0';
char *lp_p = '\0';
int lv_index = 0;
int lv_nsize = 0;
int lv_zerocount = 0;
int sign_count = 0;
int expo_count = 0;
int lv_i = 0;
int lv_j = 0;
if (lp_number[0] == '-') // The 0th position of the char array is checked for negative sign, if found sign_count is incremented.
{
sign_count++;
}
lv_zerocount = strspn(lp_number + sign_count, "0"); // the no. of Leading Zeros is calculated ignoring the negative sign if present.
if (lp_number[sign_count + lv_zerocount] == '.') //if the exponent part consists of only 0's then the zerocount is reduced by 1 to leave behind 1 zero in the exponent part.
{
lv_zerocount = lv_zerocount - 1;
}
if (lv_zerocount > 0) //the zeros are removed by being overwritten
{
memmove(lp_number + sign_count, lp_number + lv_zerocount + sign_count, strlen(lp_number));
}
while (lp_number[sign_count] != '.' && lp_number[sign_count] != '\0') //the count of remaining exponents is taken
{
expo_count++;
sign_count++;
}
lv_l = strlen(lp_number); // New string length
if (expo_count > 3) //inserting the commas
{
lv_nsize = lv_l + (expo_count / 2 - 1) + 1;
lp_fnumber = (char *)malloc(lv_nsize);
if (lp_fnumber != NULL)
{
if (lp_number[0] == '-')
{
lp_fnumber[0] = lp_number[0];
lv_j++;
memmove(lp_number, lp_number + 1, strlen(lp_number));
lv_l--;
if (expo_count % 2 != 0)
{
lp_fnumber[1] = lp_number[0];
lv_j++;
memmove(lp_number, lp_number + 1, strlen(lp_number));
expo_count--;
}
}
else if (expo_count % 2 != 0)
{
lp_fnumber[0] = lp_number[0];
lv_j = lv_j + 1;
memmove(lp_number, lp_number + 1, strlen(lp_number));
expo_count--;
}
lp_p = strchr(lp_number, '.');
if (lp_p != NULL)
{
lv_index = lp_p - lp_number;
}
while (lv_i < expo_count)
{
lp_fnumber[lv_j++] = lp_number[lv_i++];
if (lv_i + 2 < expo_count && lv_i % 2 != 0) //Alt logic:((lv_i ^ lv_l) & 1) here for every odd value of i index a comma is added.
lp_fnumber[lv_j++] = ',';
}
if (lv_index != 0)
{
while (lp_number[lv_index] != '\0')
{
lp_fnumber[lv_j++] = lp_number[lv_index++];
}
}
lp_fnumber[lv_j] = '\0';
}
return lp_fnumber;
}
else
{
return lp_number;
}
}
int main()
{
char lp_number[255];
int lv_l;
char *formated_number;
printf("Enter the lp_number\n");
fgets(lp_number, 255, stdin);
lv_l = strlen(lp_number);
formated_number = convertToInrFormat(lp_number, lv_l);
puts(formated_number);
}
setlocale(LC_NUMERIC, "en_IN");
in preference to writing a specific formatter. \$\endgroup\$LC_NUMERIC=en_IN printf "%'.3f\n" -00012345678.9
produces-1,23,45,678.900
. You can obviously experiment to see what's supported. \$\endgroup\$setlocale(LC_NUMERIC, "en_IN");
is a great way to check code, if one's platform supports"en_IN"
. Yet depending on probability needs,"en_IN"
or equivalent may not exist and one is back to rolling your own. IAC, custom code should match functionality provided viasetlocale(LC_NUMERIC, "en_IN")
. \$\endgroup\$