This question already has answers here:
Exchange 1000s digit with 10s digit (C)
(3 answers)
Closed 5 years ago.
What I want to do in C is swap two digits in a double.
For example, if the input is 54321.987 and I want to swap the 2nd with the 4th digit, the output should be 52341.987.
Example when too small: 12.34 would output 1002.34.
Using stringification approach:
There are more elegant ways, but you can see the steps (and improve on) this pseudo code to stringify, move values, and convert back to number.
char buf1[20];
char buf2[20];
char *dummy;
double val = 54321.987;
sprintf(buf1, "%9.3f", val );
//Now the number is in string form: "54321.987". Just move the two elements
buf2[0]=buf1[0];
buf2[1]=buf1[3];
buf2[2]=buf1[2];
buf2[3]=buf1[1]; //and so on
//now convert back:
val = strtod(buf2, &dummy);
printf("%9.3f\n", val);
Or, a function could be used to do essentially the same thing: (still stringification)
double swap_num_char(double num, int precision, int c1, int c2); //zero index for c1 and c2
int main(void)
{
double val = 54321.987;
printf("%9.3f\n", swap_num_char(val, 3, 1, 3));
return 0;
}
double swap_num_char(double num, int precision, int c1, int c2)
{
char buf[25];
char format[10];
char *dummy;
char c;
sprintf(format, "%s0.%df", "%", precision);
sprintf(buf, format, num);
c = buf[c1];
buf[c1] = buf[c2];
buf[c2] = c;
num = strtod(buf, &dummy);
return num;
}
You can get the two digits you're interested in with simple operations:
You can do so with
double x = 54321.987;
double tens = ((int)(x / 10)) % 10; // Result is 2
double thousands = ((int)(x / 1000)) % 10; // Result is 4
Then you can subtract out the digits from their original place,
and add them back in a new place:
x = x - (tens * 10.0) - (thousands * 1000.0); // result is 50301.987
x = x + (tens * 1000.0) + (thousands * 10.0); // result is 52341.987
Now just reduce the expression:
x = x + tens * (1000.0 - 10.0) - thousands * (1000.0 - 10.0);
This leaves you with a final expression:
x += (tens - thousands) * 990.0;
Or, if you don't want the intermediate variables:
x += (((int)(x/10))%10 - ((int)(x/1000))%10) * 990;
One solution would be to extract the digits, then swap them.
You extract the digits (from positive numbers, at least) by using floor():
int place1 = 1; /* 0-based*/
double desiredPowerOf10 = powersOf10[place1];
double nextPowerOf10 = powersOf10[place1 + 1];
double digit1 = floor(number / desiredPowerOf10) - floor(number/nextPowerOf10) * 10;
You can then subtract the digits and add them back with the different powers:
double digitsRemoved = number - (digit1 * power1 + digit2 * power2);
double digitsSwapped = digitsRemoved + digit1 * power2 + digit2 * power1;
This may be susceptible to loss of precision with very large numbers, though.
1 - Use modf() to break the number into whole and fractional parts.
double modf(double value, double *iptr);
The modf functions break the argument value into integral and fractional parts, C11 ยง7.12.6.12
2 - Print the whole number part as a string and do the swap.
3 - Reconstruct
#include <float.h>
#include <math.h>
#include <stdio.h>
double swap2_4digit(double x) {
if (signbit(x)) {
return -swap2_4digit(-x);
}
printf("Before %f\n", x);
double ipart;
double fpart = modf(x, &ipart);
// ms_digit digits '.' '\0' min_size
char buf[1 + DBL_MAX_10_EXP + 1 + 1 + 4]; // Insure buffer is big enough
strcpy(buf, "0000"); // Handle small numbers
sprintf(buf + strlen(buf), "%.0f", ipart);
size_t len = strlen(buf);
char ch = buf[len - 2];
buf[len - 2] = buf[len - 4];
buf[len - 4] = ch;
x = atof(buf) + fpart;
printf("After %f\n", x);
return x;
}
int main(void) {
swap2_4digit(54321.987);
swap2_4digit(12.34);
}
Output
Before 54321.987000
After 52341.987000
Before 12.340000
After 1002.340000
Something left for OP. Make general for other digit positions.
If you want input number to be double then you can do something like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
double numbergiven = 56789.1234;
double dummy;
double _4th_digit = (10*modf(numbergiven/10000, &dummy)) - modf(numbergiven/1000, &dummy);
double _2th_digit = (10*modf(numbergiven/100, &dummy)) - modf(numbergiven/10, &dummy);
numbergiven = numbergiven - (_4th_digit * 1000) + (_2th_digit * 1000);
numbergiven = numbergiven + (_4th_digit * 10) - (_2th_digit * 10);
printf("%lf",numbergiven);
return 0;
}
If you are not familiar with modf then you can simply do it this way:
#include <stdio.h>
#include <stdlib.h>
int main()
{
double numbergiven = 56789.1234;
int number = numbergiven;
int _4th_digit = (number/1000) - (10*(number/10000));
int _2th_digit = (number/10) - (10*(number/100));
numbergiven = numbergiven - (_4th_digit * 1000) + (_2th_digit * 1000);
numbergiven = numbergiven + (_4th_digit * 10) - (_2th_digit * 10);
printf("%lf",numbergiven);
return 0;
}
or use fmod() #John Bollinger.
The fmod functions compute the floating-point remainder of x/y.
Extract the 2 digits each with the difference of modding with 10place and modding with 10place-1.
Subtract the 2 digits and then add them back swapped.
double swap_digit(double x, unsigned a, unsigned b) {
printf("Before %f\n", x);
double a_place = pow(10.0, a);
double b_place = pow(10.0, b);
double scaled_digit_a = fmod(x, a_place) - fmod(x, a_place/10);
double scaled_digit_b = fmod(x, b_place) - fmod(x, b_place/10);
x -= scaled_digit_a + scaled_digit_b;
x += scaled_digit_a/a_place*b_place + scaled_digit_b/b_place*a_place;
printf("After %f\n", x);
return x;
}
int main(void) {
swap_digit(54321.987,2,4);
swap_digit(12.34,2,4);
}
Output
Before 54321.987000
After 52341.987000
Before 12.340000
After 1002.340000
Double is stored in a memory as a sequence of bits, but you want to operate with decimal digits. Doing this with double variable you may not receive the original digits because of floating-point arithmetic.
Therefore, you should manipulate with string representation of double. The main aspect is how many digits string will contain. But it's obvious that you get number from input. Scan it as string, not as double.
There is a working code:
#include <stdio.h>
#include <stddef.h>
#define BUFSIZE 255
void swap_digits(char *str, int n, int m) {
char *digit1 = NULL;
char *digit2 = NULL;
int count = 0;
while (*str && (!digit1 || !digit2)) {
if (*str != '.') {
count++;
if (count == n) {
digit1 = str;
}
if (count == m) {
digit2 = str;
}
}
str++;
}
if (digit1 && digit2) {
char tmp = *digit1;
*digit1 = *digit2;
*digit2 = tmp;
}
}
int main(void) {
char buffer[BUFSIZE];
scanf("%s", buffer);
// it is preferably to validate input
swap_digits(buffer, 2, 4);
printf(buffer);
return 0;
}
Related
I wrote a code for a b-adic representation of a chosen number.
#include <stdio.h>
int b_adisch (int a, int b)
{
int x, y, mod, mod1;
x = a / b;
mod1 = a % b;
printf("%i\n", mod1);
do {
y = x / b;
mod = x % b;
x = y;
printf("%i\n", mod);
} while(x != 0);
return a ;
}
int main (void)
{
int a, b;
printf("pls input a ");
scanf("%i", &a);
printf("pls input b ");
scanf("%i", &b);
b_adisch(a, b);
return 0;
}
The output order will be reversed
since the printf has to be put into the while loop and the calculation starts with the last number of the representation.
Example if a = 10 and b = 2
The output is 0101
but it should be 1010
How can I change my code to make this happen?
How can i change my code to make this happen?
2 approaches:
Compute the digits from least to most significant and save in a adequate sized buffer. This is similar to OP's approach yet saves the results of each digit's computation for later printing.
#include <assert.h>
#include <limits.h>
void b_adisch(int value, int base) {
// Let us work with simple cases first.
assert(value >= 0);
assert(base >= 2 && base <= 10);
// Adequate sized buffer
char buffer[sizeof value * CHAR_BIT + 1];
// Start at end
char *end = &buffer[sizeof buffer - 1];
*end = '\0';
do {
end--;
int digit = value%base; // Find least digit
value /= base;
*end = digit + '0'; // save the digit as text
} while (value);
printf("<%s>\n", end); // print it as a string
}
Use recursion. A more radical change; This computes and prints the output of the more significant digits first.
void b_adischR_helper(int value, int base) {
// If the value is at least 2 digits, print the most significant digits first
if (value >= base) {
b_adischR_helper(value/base, base);
}
putchar(value % base + '0'); // Print 1 digit as text
}
void b_adischR(int value, int base) {
// Let us work with simple cases first.
assert(value >= 0);
assert(base >= 2 && base <= 10);
printf("<");
b_adischR_helper(value, base);
printf(">\n");
}
Test
int main() {
b_adisch(10, 2);
b_adischR(10, 2);
b_adisch(INT_MAX, 10);
b_adischR(INT_MAX, 10);
b_adisch(INT_MAX, 2);
b_adischR(INT_MAX, 2);
}
Output
<1010>
<1010>
<2147483647>
<2147483647>
<1111111111111111111111111111111>
<1111111111111111111111111111111>
You can store the output in an array as here it is stored in "arr" and later print the output in reverse order (from end to start).
#include <stdio.h>
int arr[10000]={0};
void b_adisch (int a, int b)
{
int x, y, mod, mod1,i=0,j;
x = a / b;
mod1 = a % b;
arr[i++]=mod1;
do {
y = x / b;
mod = x % b;
x = y;
arr[i++]=mod;
} while(x != 0);
for(j=i-1;j>=0;j--)
printf("%i\n",arr[j]);
}
int main (void)
{
int a, b;
printf("pls input a ");
scanf("%i", &a);
printf("pls input b ");
scanf("%i", &b);
b_adisch(a, b);
return 0;
}
Let ib be the input base and ob the output base. str is the ASCII representation of some arbitrary large integer x. I need to define f such as:
f(str="1234567890", ib=10, ob=16) = {4, 9, 9, 6, 0, 2, 13, 2}
... where the return type of f is an int array containing the base ob digits of this integer. We assume that 2 >= ob <= MAX_INT and 2 >= ib <= 10, and str will always be a valid string (no negative needed).
Something to get OP started, but enough to leave OP to enjoy the coding experience.
// form (*d) = (*d)*a + b
static void mult_add(int *d, size_t *width, int ob, int a, int b) {
// set b as the carry
// for *width elements,
// x = (Multiply d[] by `a` (using wider than int math) and add carry)
// d[] = x mod ob
// carry = x/ob
// while (carry <> 0)
// widen d
// x = carry
// d[] = x mod ob
// carry = x/ob
}
int *ql_f(const char *src, int ib, int ob) {
// Validate input
assert(ib >= 2 && ib <= 10);
assert(ob >= 2 && ob <= INT_MAX);
assert(src);
// Allocate space
size_t length = strlen(src);
// + 2 + 4 is overkill, OP to validate and right-size later
size_t dsize = (size_t) (log(ib)/log(ob)*length + 2 + 4);
int *d = malloc(sizeof *d * dsize);
assert(d);
// Initialize d to zero
d[0] = 0;
size_t width = 1;
while (*src) {
mult_add(d, &width, ob, ib, *src - '0');
src++;
}
// add -1 to end, TBD code
return d;
}
I wrote this with older specifications, so it's not valid any more, but it might be useful as a starting point.
The code can handle long long magnitudes. Going to arbitrary precision numbers in C is a big leap!
Note using -1 as the ending marker instead of 0. Can accept ib from 2 to 36 and any ob.
Includes example main.
Function f is not reentrant as-is. To make it thread-safe, it could allocate the required memory then return a pointer to it. The simplest protocol would be having the caller responsible for freeing the memory afterwards.
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
int *f(const char *str, int ib, int ob) {
static int result[CHAR_BIT * sizeof(long long) + 1];
int i = sizeof(result) / sizeof(int) - 1;
long long l = strtoll(str, NULL, ib);
result[i--] = -1;
while (l) {
result[i] = l % ob;
l /= ob;
i--;
}
return result + i + 1;
}
int main()
{
int *x = f("1234567890", 16, 10);
while (*x > -1) {
printf("%d ", *x);
x++;
}
return 0;
}
I am getting garbage value when converting float to string. I cant use sprintf because it takes more memory and PIC24 microcontroller ram size is very low (128kb). When converting it gives some garbage values as ?39.88 like this What may be the problem . I am posting my code...
#include<stdio.h>
#include<string.h>
#include<math.h>
float Distance=0;
char str[15];
unsigned char *ftos(float f,int precision)
{
memset(str,0,sizeof(str));
float ff;
ff = f;
int a,b,c,k,l=0,m,i=0;
// check for negative float
if(f<0.0)
{
str[i++]='-';
f*=-1;
}
a=f; // extracting whole number
f-=a; // extracting decimal part
k = precision;
// number of digits in whole number
while(k>0)
{
l = pow(10.0f,k);
m = a/l;
if(m>0)
{
break;
}
k--;
}
// number of digits in whole number are k+1
/*
extracting most significant digit i.e. right most digit , and concatenating to string
obtained as quotient by dividing number by 10^k where k = (number of digit -1)
*/
for(l=k+1;l>0;l--)
{
b = pow(10.0f,l-1);
c = a/b;
str[i++]=c+48;
a%=b;
}
str[i++] = '.';
/* extracting decimal digits till precision */
for(l=0;l<precision;l++)
{
f*=10.0;
b = f;
str[i++]=b+48;
f-=b;
}
str[i]='\0';
return str;
}
void distance(float lat1, float lon1, float lat2, float lon2)
{
float dlon=0,dlat=0,a=0,c=0,dist=0;
dlon = (lon2 - lon1) * (M_PI / 180.0);
dlat = (lat2 - lat1) * (M_PI / 180.0);
a = pow(sin(dlat/2.0), 2) + cos(lat1*(M_PI / 180.0)) * cos(lat2*(M_PI / 180.0)) * pow(sin(dlon/2.0), 2);
c = 2 * atan2(sqrt(a), sqrt(1-a));
dist = 6367 * c;
Distance += dist;
}
int main()
{
distance(13.00659,80.121212,13.69898,80.256987);
printf("%s\n",ftos(Distance,6));
}
when i print the distance value after conversion it gives some garbage value... why?
I'm coding for a microcontroller-based application and I need to convert a float to a character string, but I do not need the heavy overhead associated with sprintf(). Is there any eloquent way to do this? I don't need too much. I only need 2 digits of precision.
Here's a version optimized for embedded systems that doesn't require any stdio or memset, and has low memory footprint. You're responsible for passing a char buffer initialized with zeros (with pointer p) where you want to store your string, and defining CHAR_BUFF_SIZE when you make said buffer (so the returned string will be null terminated).
static char * _float_to_char(float x, char *p) {
char *s = p + CHAR_BUFF_SIZE; // go to end of buffer
uint16_t decimals; // variable to store the decimals
int units; // variable to store the units (part to left of decimal place)
if (x < 0) { // take care of negative numbers
decimals = (int)(x * -100) % 100; // make 1000 for 3 decimals etc.
units = (int)(-1 * x);
} else { // positive numbers
decimals = (int)(x * 100) % 100;
units = (int)x;
}
*--s = (decimals % 10) + '0';
decimals /= 10; // repeat for as many decimal places as you need
*--s = (decimals % 10) + '0';
*--s = '.';
while (units > 0) {
*--s = (units % 10) + '0';
units /= 10;
}
if (x < 0) *--s = '-'; // unary minus sign for negative numbers
return s;
}
Tested on ARM Cortex M0 & M4. Rounds correctly.
Try this. It should be nice and small. I've output the string directly - doing a printf, rather than a sprintf. I'll leave it to you to allocate space for the return string, as well as copying the result into it.
// prints a number with 2 digits following the decimal place
// creates the string backwards, before printing it character-by-character from
// the end to the start
//
// Usage: myPrintf(270.458)
// Output: 270.45
void myPrintf(float fVal)
{
char result[100];
int dVal, dec, i;
fVal += 0.005; // added after a comment from Matt McNabb, see below.
dVal = fVal;
dec = (int)(fVal * 100) % 100;
memset(result, 0, 100);
result[0] = (dec % 10) + '0';
result[1] = (dec / 10) + '0';
result[2] = '.';
i = 3;
while (dVal > 0)
{
result[i] = (dVal % 10) + '0';
dVal /= 10;
i++;
}
for (i=strlen(result)-1; i>=0; i--)
putc(result[i], stdout);
}
// convert float to string one decimal digit at a time
// assumes float is < 65536 and ARRAYSIZE is big enough
// problem: it truncates numbers at size without rounding
// str is a char array to hold the result, float is the number to convert
// size is the number of decimal digits you want
void FloatToStringNew(char *str, float f, char size)
{
char pos; // position in string
char len; // length of decimal part of result
char* curr; // temp holder for next digit
int value; // decimal digit(s) to convert
pos = 0; // initialize pos, just to be sure
value = (int)f; // truncate the floating point number
itoa(value,str); // this is kinda dangerous depending on the length of str
// now str array has the digits before the decimal
if (f < 0 ) // handle negative numbers
{
f *= -1;
value *= -1;
}
len = strlen(str); // find out how big the integer part was
pos = len; // position the pointer to the end of the integer part
str[pos++] = '.'; // add decimal point to string
while(pos < (size + len + 1) ) // process remaining digits
{
f = f - (float)value; // hack off the whole part of the number
f *= 10; // move next digit over
value = (int)f; // get next digit
itoa(value, curr); // convert digit to string
str[pos++] = *curr; // add digit to result string and increment pointer
}
}
While you guys were answering I've come up with my own solution which that works better for my application and I figure I'd share. It doesn't convert the float to a string, but rather 8-bit integers. My range of numbers is very small (0-15) and always non-negative, so this will allow me to send the data over bluetooth to my android app.
//Assumes bytes* is at least 2-bytes long
void floatToBytes(byte_t* bytes, float flt)
{
bytes[1] = (byte_t) flt; //truncate whole numbers
flt = (flt - bytes[1])*100; //remove whole part of flt and shift 2 places over
bytes[0] = (byte_t) flt; //truncate the fractional part from the new "whole" part
}
//Example: 144.2345 -> bytes[1] = 144; -> bytes[0] = 23
I can't comment on enhzflep's response, but to handle negative numbers correctly (which the current version does not), you only need to add
if (fVal < 0) {
putc('-', stdout);
fVal = -fVal;
}
at the beginning of the function.
Its a Liitle large method, but It would work for both int and float, decimalPoint parameter is passed with zero value for Integer, Please let me know if you have smaller function than this.
void floatToStr(uint8_t *out, float x,int decimalPoint)
{
uint16_t absval = fabs(x);
uint16_t absvalcopy = absval;
int decimalcount = 0;
while(absvalcopy != 0)
{
absvalcopy /= 10;
decimalcount ++;
}
uint8_t *absbuffer = malloc(sizeof(uint8_t) * (decimalcount + decimalPoint + 1));
int absbufferindex = 0;
absvalcopy = absval;
uint8_t temp;
int i = 0;
for(i = decimalcount; i > 0; i--)
{
uint16_t frst1 = fabs((absvalcopy / pow(10.0, i-1)));
temp = (frst1 % 10) + 0x30;
*(absbuffer + absbufferindex) = temp;
absbufferindex++;
}
if(decimalPoint > 0)
{
*(absbuffer + absbufferindex) = '.';
absbufferindex ++;
//------------------- Decimal Extractor ---------------------//
for(i = 1; i < decimalPoint + 1; i++)
{
uint32_t valueFloat = (x - (float)absval)*pow(10,i);
*(absbuffer + absbufferindex) = ((valueFloat) % 10) + 0x30;
absbufferindex++;
}
}
for(i=0; i< (decimalcount + decimalPoint + 1); i++)
{
*(out + i) = *(absbuffer + i);
}
i=0;
if(decimalPoint > 0)
i = 1;
*(out + decimalcount + decimalPoint + i) = 0;
}
I'm working on a program that regards with currency. Ive been finding a solution to display money values decently like this:
9,999.99 USD
Remember when assigning a certain variable with a value (money), you musn't insert commas.
I.e.:
double money=9999.99;
And when accessing it;
printf("%.2l USD",money);
Which will output:
9999.99 USD
This is not what I want, especially on bigger amounts exceeding the hundredth, thousandth, millionth, or even billionth place value.
Now I can't find any solution than printing out the desired output directly on the printf.
printf("9,999.99");
Which is undesirable with many variables.
Can anyone help me out?
Please take a look and printf manual page taking note of the following bit:
*"For some numeric conversions a radix character ("decimal point") or thousands' grouping character is used. The actual character used depends on the LC_NUMERIC part of the locale. The POSIX locale uses '.' as radix character, and does not have a grouping character. Thus,
printf("%'.2f", 1234567.89);
results in "1234567.89" in the POSIX locale, in "1234567,89" in the nl_NL locale, and in "1.234.567,89" in the da_DK locale."*
This can be changed by the function setlocale
There is a function, strfmon which might be able to help you
First, don't use floating-point types to represent money because normally floating-point types are binary and as such cannot represent all decimal fractions (cents) exactly, further these types are prone to rounding errors. Use integers instead and count cents instead of dollars.
#include <stdio.h>
#include <limits.h>
unsigned long long ConstructMoney(unsigned long long dollars, unsigned cents)
{
return dollars * 100 + cents;
}
void PrintWithCommas(unsigned long long n)
{
char s[sizeof n * CHAR_BIT + 1];
char *p = s + sizeof s;
unsigned count = 0;
*--p = '\0';
do
{
*--p = '0' + n % 10;
n /= 10;
if (++count == 3 && n)
{
*--p = ',';
count = 0;
}
} while (n);
printf("%s", p);
}
void PrintMoney(unsigned long long n)
{
PrintWithCommas(n / 100);
putchar('.');
n %= 100;
putchar('0' + n / 10);
putchar('0' + n % 10);
}
int main(void)
{
PrintMoney(ConstructMoney(0, 0)); puts("");
PrintMoney(ConstructMoney(0, 1)); puts("");
PrintMoney(ConstructMoney(1, 0)); puts("");
PrintMoney(ConstructMoney(1, 23)); puts("");
PrintMoney(ConstructMoney(12, 34)); puts("");
PrintMoney(ConstructMoney(123, 45)); puts("");
PrintMoney(ConstructMoney(1234, 56)); puts("");
PrintMoney(ConstructMoney(12345, 67)); puts("");
PrintMoney(ConstructMoney(123456, 78)); puts("");
PrintMoney(ConstructMoney(1234567, 89)); puts("");
return 0;
}
Output (ideone):
0.00
0.01
1.00
1.23
12.34
123.45
1,234.56
12,345.67
123,456.78
1,234,567.89
If you're using the standard library, there's no way to do this -- you have to write some code that does it by hand.
I would recommend multiplying the value by 100, casting to integer, and printing the digits with separators as needed -- it's much easier to handle individual digits on an integer.
The following code, for instance, will fill a char * buffer with the string representation of the value you have:
void formatString (double number, char * buffer) {
if (number < 0) {
*buffer = '-';
formatString(number, buffer + 1);
return;
}
unsigned long long num = (unsigned long long) (number * 100);
unsigned long long x; // temporary storage for counting the digits
unsigned char digits;
for (x = num / 1000, digits = 1; x; digits ++, x /= 10);
// counts the digits, also ensures that there's at least one digit
unsigned char pos; // digit position
for (pos = 1, x = 100; pos < digits; pos ++, x *= 10);
// reuses x as a value for extracting the digit in the needed position;
char * current = buffer;
for (pos = digits; pos; pos --) {
*(current ++) = 48 + (num / x);
// remember 48 + digit gives the ASCII for the digit
if (((pos % 3) == 1) && (pos > 1)) *(current ++) = ',';
num %= x;
x /= 10;
}
*(current ++) = '.';
*(current ++) = 48 + num / 10;
*(current ++) = 48 + num % 10;
*current = 0;
}