Drawing simultaneously sine and cosine curves - c

I'm trying to write a c program that draws sine and cosine curves simultaneously by using '+' for sine and 'x' for cosine and '*' when the values of sine and cosine are equal. Here is the code:
#include<stdio.h>
#include<math.h> /* for sin(x) */
#define M_PI 3.14159265358979323846264338327950288
int main() {
double x;
int s_indent;
int c_indent;
for(x = -180.0; x <=180.0; x+=15.0) {
/* compute value */
s_indent = 10 + 10* sin(x/180 * M_PI);
c_indent = 10 + 10* cos(x/180 * M_PI);
if(c_indent == s_indent){
for(;s_indent;--s_indent) putchar(' ');
printf("*\n");
}
else{
for(; s_indent; --s_indent) putchar(' ');
printf("+\n");
/* plot x at position */
for(; c_indent; --c_indent) putchar(' ');
printf("x\n");
}
}
return 0;
}
but the problem with the code is that it produces the curves line by line. Like here:
And I want to make it on the same line like this one here:
Thoughts?

You can: create an empty line
char line[] = " ";
set the characters at the appropriate places
line[c_indent] = 'x';
line[s_indent] = '+';
and then output this line:
puts(line);
The case of both sine and cos in a single point is left to you as an exercise ;)

In the posted code, each symbol is printed in a separate line at the calculated position, but what you have to do is to determine the order of the symbols and print both in the same line.
Consier using a simple function like
void print_after_n_spaces(int n, const char* str)
{
while (n-- > 0)
putchar(' ');
printf("%s", str);
}
Also, add another branch and calculate the difference between the two positions:
for(int x = -180; x <= 180; x += 15)
{
double angle = x / 180.0 * M_PI;
int s_pos = 10.5 + 10.0 * sin(angle);
int c_pos = 10.5 + 10.0 * cos(angle);
// ^^^^ To "round" the values
if (c_pos > s_pos)
{
print_after_n_spaces(s_pos, "+");
// ^^^ Don't print the newline here
print_after_n_spaces(c_pos - s_pos - 1, "x\n");
// ^^^^^^^^^^^^^^^^^ Difference between the positions
}
else if (c_pos < s_pos)
{
// Here prints first the "x" (the cosine), then the "+"
}
else
{
// Here prints only "*"
}
}

In the else statement, check which one that is larger of s_indent and c_indent.
Copy these variables to two new variables largest and smallest.
Iterate with for loop over smallest to print spaces, then print either + or x depending on which was smallest.
Then iterate from smallest to largest, print spaces, then print either + or x depending on which was largest.
An alternative, more elegant solution is to make a function void printline (int n, char symbol) then call it two times.

Related

Recursive Flood Fill algorithm in C using ASCII art and incrementing characters to fill the space

I have an assignment where I need to write a recursive flood fill algorithm to fill in spaces in ASCII art with incrementing characters. Now, I have done endless research and think I understand the basic fundamentals of this algorithm. However, when I apply what I learned, the output does not produce what I want. The following is the outline of the program
Find the 'A' within the room where an '*' represents a wall. You can assume there will always be an 'A'.
Start at A and fill the room with incrementing characters up until Z and keep going with Z if Z is reached. Example output:
*****
*DCB*
***A*
*DCB*
*****
Below is a sample program as the original is much bigger.
#include <stdio.h>
#include <stdlib.h>
typedef struct room{
char **array;
int rows;
int cols;
} room;
void printRoom(room room);
int *findA(room room);
void floodFill(room room, int x, int y, char paint);
int main(int argc, char *argv[]){
// Make a new room
room newRoom;
// Set the rows and columns
newRoom.rows = 5;
newRoom.cols = 5;
// Allocate memory for the array
newRoom.array = malloc(newRoom.rows * sizeof(char*));
for(int i = 0; i < newRoom.rows; i++){
newRoom.array[i] = malloc(newRoom.cols * sizeof(char));
}
// Fill the first array with "*****"
for(int i = 0; i < newRoom.cols; i++){
newRoom.array[0][i] = '*';
}
// Fill the second array with "* *"
newRoom.array[1][0] = '*';
newRoom.array[1][1] = ' ';
newRoom.array[1][2] = ' ';
newRoom.array[1][3] = ' ';
newRoom.array[1][4] = '*';
// Fill the third array with "**A*"
newRoom.array[2][0] = '*';
newRoom.array[2][1] = '*';
newRoom.array[2][2] = '*';
newRoom.array[2][3] = 'A';
newRoom.array[2][4] = '*';
// Fill the fourth array with "* *"
newRoom.array[3][0] = '*';
newRoom.array[3][1] = ' ';
newRoom.array[3][2] = ' ';
newRoom.array[3][3] = ' ';
newRoom.array[3][4] = '*';
// Fill the fifth array with "*****"
for(int i = 0; i < newRoom.cols; i++){
newRoom.array[4][i] = '*';
}
printf("Before\n");
printRoom(newRoom);
// Find the A
int *a = findA(newRoom);
// Print the A
printf("A is at %d, %d\n", a[0], a[1]);
// Flood fill the room
floodFill(newRoom, a[0], a[1], 'A');
// Print the room
printf("\nAfter\n");
printRoom(newRoom);
return 0;
}
int *findA(room room){
int *location = malloc(2 * sizeof(int));
for(int i = 0; i < room.rows; i++){
for(int j = 0; j < room.cols; j++){
if(room.array[i][j] == 'A'){
location[0] = i;
location[1] = j;
}
}
}
return location;
}
void floodFill(room room, int x, int y, char paint){
// If the current position is a wall, return
if(room.array[x][y] == '*'){
return;
}
// If the current position is already painted, return
if(room.array[x][y] == paint){
return;
}
if(x < 0 || x >= room.rows || y < 0 || y >= room.cols){
return;
}
// Paint the current position
room.array[x][y] = paint;
// Flood fill the left position
floodFill(room, x, y + 1, paint);
// Flood fill the right position
floodFill(room, x, y - 1, paint);
// Flood fill the top position
floodFill(room, x + 1, y, paint);
// Flood fill the bottom position
floodFill(room, x - 1, y, paint);
}
void printRoom(room room){
for(int i = 0; i < room.rows; i++){
for(int j = 0; j < room.cols; j++){
printf("%c", room.array[i][j]);
}
printf("\n");
}
}
Output
Before
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
* *
***A*
* *
*****
What I think part of the problem is that in the version above, when the first call to floodFill is made, it checks if the current position is equal to paint. In this case it is and then immediately returns and does nothing. However, if I change this line:
From
floodFill(newRoom, a[0], a[1], 'A');
To
floodFill(newRoom, a[1], a[0], 'A');
Output
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
* *
***A*
*AAA*
*****
As you can see it somewhat filled out the bottom half but not the top. What I think is happening here is that since A is already there when it tries to go up, it exits as the current position is already A when the room was made. Now I'm not sure what to do as I keep getting stuck. If I try to change the base cases I will get infinite recursive calls or it will not do anything at all. In addition, I'm not sure if I need two char parameters in the floodFill function (char oldPaint, char newPaint) to handle the incrementing of characters. Any help is greatly appreciated!
There are these issues:
The algorithm stops immediately, because it finds that at position x, y the paint character ('A') is already there. To solve this, I would write a wrapper function (floodFillStart) that first replaces that 'A' with a space, and then calls floodFill.
The check whether the x and y coordinate are out of range, should happen before any access to the matrix. So that if statement should come first.
The logic to fill with the next character is missing.
The check room.array[x][y] == paint is not good enough once the character is changing: the algorithm will bump into a character that has the preceding value (where the "flood" came from). This could read room.array[x][y] != ' ', so performing the wall-check at the same time.
void floodFill(room room, int x, int y, char paint){
// First this
if(x < 0 || x >= room.rows || y < 0 || y >= room.cols){
return;
}
// If the current position is not a free spot...
if(room.array[x][y] != ' '){
return;
}
room.array[x][y] = paint;
// Increment the character to paint with
if (paint < 'Z') {
paint++;
}
floodFill(room, x, y + 1, paint);
floodFill(room, x, y - 1, paint);
floodFill(room, x + 1, y, paint);
floodFill(room, x - 1, y, paint);
}
void floodFillStart(room room, int x, int y){
// Temporarily clear the starting spot
if (room.array[x][y] == 'A') {
room.array[x][y] = ' ';
}
floodFill(room, x, y, 'A');
}
In the main program call:
floodFillStart(room, x, y);
The problem is that, at the start, the initial cell already contains an A character, so the function immediately returns. One approach is to clear the initial cell before calling floodFill the first time from main, as follows:
// Flood fill the room
newRoom.array[a[0]][a[1]] = ' ';
floodFill(newRoom, a[0], a[1], 'A');
This produces the following output:
Before
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
*AAA*
***A*
*AAA*
*****

When I want to draw B-spline curves I have a loop problem

I want to draw b spline curves. I used the binomial expansion for this and I created a function that calculates factorial.
int faktoriyel(int don)
{
int a=1;
if(don!=0)
{
for(int i=don-1; i>0; i--)
{
don=don*i;
}
}
else
{
don=a;
}
return don;
}
when I want to draw with too many pixels.The for loop is problematic.I have 2 variables:t and k.It needs to form the binomial expansion according to the number of points entered, but it causes problems because of nested loops.
double xtoplam1;
double ytoplam1;
int a,b,c;
int n=sayac-2,k=0;
double t=0.0;
int u=sayac-1;
double xtoplam=0;
double ytoplam=0;
for (t=0.0; t<1.0; t=t+0.0005)
{
xtoplam1= pow(1-t,u-1)*noktalar[0].x;
ytoplam1= pow(1-t,u-1)*noktalar[1].y;
while(k+1<=sayac-1)
{
a=faktoriyel(n);
printf("a:%d\n",a);
b=faktoriyel(k);
printf("b:%d\n",b);
c=faktoriyel(n-k);
printf("c:%d\n",c);
xtoplam = (a/(b*c))*pow(1-t,k+1)*pow(t,n)*noktalar[k+1].x;
ytoplam = (a/(b*c))*pow(1-t,k+1)*pow(t,n)*noktalar[k+1].y;
k++;
}
putpixel (getmaxx()/2+((xtoplam+xtoplam1)*20),getmaxy()/2-((ytoplam+ytoplam1)*20), RED);
printf("x:%f\ny:%f\n",xtoplam+xtoplam1,ytoplam+ytoplam1);
}
How can I fix that.I mean for example I have 2 points.Then function must be pow(1-t, 3) * x[0] + 3 * t * pow (1-t, 2) * x[1] + 3 * pow (t, 2) * (1-t) * x[2] + pow (t, 3) * x[3] Then "t" should go from 0.0005 to 1
EDIT:
I can also use tables for this situation but I think it is so primitive for me. For example:
EDIT:
if(sayac-1==4)
{
for (t=0.0; t<1.0; t=t+0.0005)
{
xtoplam = pow(1-t,3)*noktalar[0].x+3*pow(1-t,2)*pow(t,1)*noktalar[1].x+3*pow(1-t,1)*pow(t,2)*noktalar[2].x+pow(t,3)*noktalar[3].x;
ytoplam = pow(1-t,3)*noktalar[0].y+3*pow(1-t,2)*pow(t,1)*noktalar[1].y+3*pow(1-t,1)*pow(t,2)*noktalar[2].y+pow(t,3)*noktalar[3].y;
putpixel (getmaxx()/2+((xtoplam)*20),getmaxy()/2-((ytoplam)*20), RED);
}
}
This is working well.

How to convert a char* to a number function with a comma (decimal point)?

I wrote change() to help me convert a string to a double.
For example: if the string is "5.5", I want the number to be 5.5. If the string is "0.0", I want the number to be 0. Another example: "50" to 50.
Now the problem is when I use the change() with pow() that is in the library math.h, everything works perfectly fine and I tested it with a lot of inputs and all worked perfect.
Example to a test :
change("5.0") gives me 5
change("1.5") gives me 1.5
Since I can't use the library math I wrote power(), but when I test change(), now I don't get an output. I think it is stuck in an infinite loop.
Any help why this thing is happening?
double change(char* Point) {
int count = 0;
double res = 0;
while (*Point == '0') {
Point++;
}
while (*Point != '.' && *Point) {
count++;
Point++;
}
int num1 = 0;
for (int i = 0; i < count; i++) {
Point--;
num1 = (*Point - '0') * (power(10, i));
}
int i = -1;
while (*Point != '.' && *Point) {
Point++;
}
double num2 = 0;
if (!*Point) {
return res = (double) num1 + num2;
}
Point++;
while (*Point) {
num2 = (double) (*Point - '0') * (double) (power(10, i));
i--;
Point++;
}
res = (double) num1 + num2;
return res;
}
I also wrote the function power:
int power(int base,int exp)
{
int result=1;
if(exp == 0){
return 1;
}
while (exp != 0)
{
result=result*base;
exp--;
}
return result;
}
Because you call the function power(10,i) in the change function, while i have a negative value. You can fix this by adding an if statement in your power function
if (exp < 0) {
exp = 0 - exp;
return(1/power(base,exp));
}
Edit : you also have to change the power function to return double instead of int
you can convert a string to a float using atof()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
float val;
char str[20];
strcpy(str, "98993489");
val = atof(str);
printf("String value = %s, Float value = %f\n", str, val);
return(0);
source of code : https://www.tutorialspoint.com/c_standard_library/c_function_atof.htm
As already established, the problem is this loop will never end if exp is less than 0 in your power function.
while (exp != 0)
{
result=result*base;
exp--;
}
But your code still won't work if you fix this because you're only ever storing one digit in num1
num1 = (*Point - '0') * (power(10, i));
If you pass in, for example, "50" it'll work fine and you'll get 50 back, but if you pass in "54" you'll also get 50 as you lose the 4.
You need to add the newly calculated digit to the existing value like so.
num1 += (*Point - '0') * (power(10, i));
You can greatly simplify that first bit of the function and remove the need to use power though by realising that as you move through the string, you can just multiple the current value of num1 by 10 and then add on the new digit. This means you only process the string before the decimal point just once rather than 3 times.
int num1 = 0;
for(;isdigit(*Point);Point++) {
num1 *= 10;
num1 += *Point - '0';
}
I've also replaced *Point != '.' && *Point with isdigit(*Point) (from "ctype.h") as that ensures that if it encounters something that isn't a number character, it doesn't try turning it into a number - you should stop processing completely at that point.
You could remove the need for power completely by using the same idea for calculating num2 as well since the amount you're dividing *Point - '0' also increases by 10 each time.

omitting a printf causes an incorrect answer

For some reason I was getting a dramatically incorrect answer for a problem, so I put in this printf to try and debug.
for (s = 0; s <= 100; s++) {
for (t = 0; t <= 100; t++) {
printf("At (%f,%f), spl = %f\n", s, t, spl(loc_data, s, t)); */
if (spl(loc_data, s, t) > 80) {
p++;
}
}
}
If I omit the printf line, I get an incorrect answer. I think that it has something to do with memory allocation or uninitialised variables, but this is beyond my abilities. Any help would be appreciated.
Whole code:
#include <stdio.h>
#include <math.h>
typedef struct {
double x;
double y;
double W;
} data_t;
double spl(data_t *, double, double);
int main(int argc, char **argv) {
data_t loc_data[1000];
double spl0, p = 0, pp;
int i = 0, j = 0;
double s, t;
while (scanf("%lf %lf %lf", &loc_data[i].x, &loc_data[i].y, &loc_data[i].W) == 3) {
i++;
}
printf("\nStage 1\n=======\n");
printf("Number of sound sources: %d\n", i);
for (j = 0; j < i; j++) {
printf("%.1f meters east, %.1f meters north, power %1.5f Watts\n",
loc_data[j].x, loc_data[j].y, loc_data[j].W);
}
printf("\nStage 2\n=======\n");
spl0 = spl(loc_data, 0, 0);
printf("SPL at (0.0,0.0): %.1f dB\n", spl0);
printf("\nStage 3\n=======\n");
for (s = 0; s <= 100; s++) {
for (t = 0; t <= 100; t++) {
printf("At (%f,%f), spl = %f\n", s, t, spl(loc_data, s, t));
if (spl(loc_data, s, t) > 80) {
p++;
}
}
}
pp = p / 102.01;
printf("Points sampled: 10201\nAbove 80.0 dB: %.1f%%\n", pp);
return 0;
}
double spl(data_t *loc_data, double pointx, double pointy) {
int i = 0;
double r_sq, powi, spli, spl;
while (loc_data[i].W != 0) {
r_sq = pow(loc_data[i].x - pointx,2) + pow(loc_data[i].y - pointy,2);
powi = 10*log10(loc_data[i].W / pow(10,-12));
spli = powi + 10*log10((2 / (4 * M_PI * r_sq)) + (4 / (2.5 * M_PI * r_sq)));
spl = 10*log10(pow(10, spl/10) + pow(10, spli/10));
i++;
}
return spl;
}
Apologies for the poor formatting.
You''re using a variable (spl) before it's initialized inthe function spl():
double spl(data_t *loc_data, double pointx, double pointy) {
int i = 0;
double r_sq, powi, spli, spl;
while (loc_data[i].W != 0) {
r_sq = pow(loc_data[i].x - pointx,2) + pow(loc_data[i].y - pointy,2);
powi = 10*log10(loc_data[i].W / pow(10,-12));
spli = powi + 10*log10((2 / (4 * M_PI * r_sq)) + (4 / (2.5 * M_PI * r_sq)));
spl = 10*log10(pow(10, spl/10) + pow(10, spli/10));
// ^^^
i++;
}
return spl;
}
Calling printf() is probably influencing the value the variable happens to have.
Also, you read in a number of entries into the loc_data array, but don't pass that information to the spl() function. In spl() you treat the array entry with field W as the 'sentinel' - the end of the array. Is it a given that the last entry in the input data will have a zero value? If so, you should probably let us know, and probably check for that when done reading the input.
You are not initializing the loc_data entries in any way, which means they will contain garbage. After you scanf the entries (make sure to stop reading after you read 1000 lines), fill the remaining elements of the array with zeroes. I know you said you already tried this, but it's not visible in the code you posted.
Additionally, you should pass i (after giving it a better name) into the spl function so it knows how many good sources you have, instead of looking for a 0 as a terminator, which might not exist if you have 1000 good sources, or might exist too early if some source has a power of 0.

Avoid trailing zeroes in printf()

I keep stumbling on the format specifiers for the printf() family of functions. What I want is to be able to print a double (or float) with a maximum given number of digits after the decimal point. If I use:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
I get
359.013
359.010
Instead of the desired
359.013
359.01
Can anybody help me?
This can't be done with the normal printf format specifiers. The closest you could get would be:
printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01); // 359.01
but the ".6" is the total numeric width so
printf("%.6g", 3.01357); // 3.01357
breaks it.
What you can do is to sprintf("%.20g") the number to a string buffer then manipulate the string to only have N characters past the decimal point.
Assuming your number is in the variable num, the following function will remove all but the first N decimals, then strip off the trailing zeros (and decimal point if they were all zeros).
char str[50];
sprintf (str,"%.20g",num); // Make the number.
morphNumericString (str, 3);
: :
void morphNumericString (char *s, int n) {
char *p;
int count;
p = strchr (s,'.'); // Find decimal point, if any.
if (p != NULL) {
count = n; // Adjust for more or less decimals.
while (count >= 0) { // Maximum decimals allowed.
count--;
if (*p == '\0') // If there's less than desired.
break;
p++; // Next character.
}
*p-- = '\0'; // Truncate string.
while (*p == '0') // Remove trailing zeros.
*p-- = '\0';
if (*p == '.') { // If all decimals were zeros, remove ".".
*p = '\0';
}
}
}
If you're not happy with the truncation aspect (which would turn 0.12399 into 0.123 rather than rounding it to 0.124), you can actually use the rounding facilities already provided by printf. You just need to analyse the number before-hand to dynamically create the widths, then use those to turn the number into a string:
#include <stdio.h>
void nDecimals (char *s, double d, int n) {
int sz; double d2;
// Allow for negative.
d2 = (d >= 0) ? d : -d;
sz = (d >= 0) ? 0 : 1;
// Add one for each whole digit (0.xx special case).
if (d2 < 1) sz++;
while (d2 >= 1) { d2 /= 10.0; sz++; }
// Adjust for decimal point and fractionals.
sz += 1 + n;
// Create format string then use it.
sprintf (s, "%*.*f", sz, n, d);
}
int main (void) {
char str[50];
double num[] = { 40, 359.01335, -359.00999,
359.01, 3.01357, 0.111111111, 1.1223344 };
for (int i = 0; i < sizeof(num)/sizeof(*num); i++) {
nDecimals (str, num[i], 3);
printf ("%30.20f -> %s\n", num[i], str);
}
return 0;
}
The whole point of nDecimals() in this case is to correctly work out the field widths, then format the number using a format string based on that. The test harness main() shows this in action:
40.00000000000000000000 -> 40.000
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.010
359.00999999999999090505 -> 359.010
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122
Once you have the correctly rounded value, you can once again pass that to morphNumericString() to remove trailing zeros by simply changing:
nDecimals (str, num[i], 3);
into:
nDecimals (str, num[i], 3);
morphNumericString (str, 3);
(or calling morphNumericString at the end of nDecimals but, in that case, I'd probably just combine the two into one function), and you end up with:
40.00000000000000000000 -> 40
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.01
359.00999999999999090505 -> 359.01
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122
To get rid of the trailing zeros, you should use the "%g" format:
float num = 1.33;
printf("%g", num); //output: 1.33
After the question was clarified a bit, that suppressing zeros is not the only thing that was asked, but limiting the output to three decimal places was required as well. I think that can't be done with sprintf format strings alone. As Pax Diablo pointed out, string manipulation would be required.
I like the answer of R. slightly tweaked:
float f = 1234.56789;
printf("%d.%.0f", f, 1000*(f-(int)f));
'1000' determines the precision.
Power to the 0.5 rounding.
EDIT
Ok, this answer was edited a few times and I lost track what I was thinking a few years back (and originally it did not fill all the criteria). So here is a new version (that fills all criteria and handles negative numbers correctly):
double f = 1234.05678900;
char s[100];
int decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf("10 decimals: %d%s\n", (int)f, s+1);
And the test cases:
#import <stdio.h>
#import <stdlib.h>
#import <math.h>
int main(void){
double f = 1234.05678900;
char s[100];
int decimals;
decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf("10 decimals: %d%s\n", (int)f, s+1);
decimals = 3;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" 3 decimals: %d%s\n", (int)f, s+1);
f = -f;
decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" negative 10: %d%s\n", (int)f, s+1);
decimals = 3;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" negative 3: %d%s\n", (int)f, s+1);
decimals = 2;
f = 1.012;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" additional : %d%s\n", (int)f, s+1);
return 0;
}
And the output of the tests:
10 decimals: 1234.056789
3 decimals: 1234.057
negative 10: -1234.056789
negative 3: -1234.057
additional : 1.01
Now, all criteria are met:
maximum number of decimals behind the zero is fixed
trailing zeros are removed
it does it mathematically right (right?)
works (now) also when first decimal is zero
Unfortunately this answer is a two-liner as sprintf does not return the string.
Why not just do this?
double f = 359.01335;
printf("%g", round(f * 1000.0) / 1000.0);
I search the string (starting rightmost) for the first character in the range 1 to 9 (ASCII value 49-57) then null (set to 0) each char right of it - see below:
void stripTrailingZeros(void) {
//This finds the index of the rightmost ASCII char[1-9] in array
//All elements to the left of this are nulled (=0)
int i = 20;
unsigned char char1 = 0; //initialised to ensure entry to condition below
while ((char1 > 57) || (char1 < 49)) {
i--;
char1 = sprintfBuffer[i];
}
//null chars left of i
for (int j = i; j < 20; j++) {
sprintfBuffer[i] = 0;
}
}
What about something like this (might have rounding errors and negative-value issues that need debugging, left as an exercise for the reader):
printf("%.0d%.4g\n", (int)f/10, f-((int)f-(int)f%10));
It's slightly programmatic but at least it doesn't make you do any string manipulation.
Some of the highly voted solutions suggest the %g conversion specifier of printf. This is wrong because there are cases where %g will produce scientific notation. Other solutions use math to print the desired number of decimal digits.
I think the easiest solution is to use sprintf with the %f conversion specifier and to manually remove trailing zeros and possibly a decimal point from the result. Here's a C99 solution:
#include <stdio.h>
#include <stdlib.h>
char*
format_double(double d) {
int size = snprintf(NULL, 0, "%.3f", d);
char *str = malloc(size + 1);
snprintf(str, size + 1, "%.3f", d);
for (int i = size - 1, end = size; i >= 0; i--) {
if (str[i] == '0') {
if (end == i + 1) {
end = i;
}
}
else if (str[i] == '.') {
if (end == i + 1) {
end = i;
}
str[end] = '\0';
break;
}
}
return str;
}
Note that the characters used for digits and the decimal separator depend on the current locale. The code above assumes a C or US English locale.
A simple solution but it gets the job done, assigns a known length and precision and avoids the chance of going exponential format (which is a risk when you use %g):
// Since we are only interested in 3 decimal places, this function
// can avoid any potential miniscule floating point differences
// which can return false when using "=="
int DoubleEquals(double i, double j)
{
return (fabs(i - j) < 0.000001);
}
void PrintMaxThreeDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%.1f", d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%.2f", d);
else
printf("%.3f", d);
}
Add or remove "elses" if you want a max of 2 decimals; 4 decimals; etc.
For example if you wanted 2 decimals:
void PrintMaxTwoDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%.1f", d);
else
printf("%.2f", d);
}
If you want to specify the minimum width to keep fields aligned, increment as necessary, for example:
void PrintAlignedMaxThreeDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%7.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%9.1f", d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%10.2f", d);
else
printf("%11.3f", d);
}
You could also convert that to a function where you pass the desired width of the field:
void PrintAlignedWidthMaxThreeDecimal(int w, double d)
{
if (DoubleEquals(d, floor(d)))
printf("%*.0f", w-4, d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%*.1f", w-2, d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%*.2f", w-1, d);
else
printf("%*.3f", w, d);
}
I found problems in some of the solutions posted. I put this together based on answers above. It seems to work for me.
int doubleEquals(double i, double j) {
return (fabs(i - j) < 0.000001);
}
void printTruncatedDouble(double dd, int max_len) {
char str[50];
int match = 0;
for ( int ii = 0; ii < max_len; ii++ ) {
if (doubleEquals(dd * pow(10,ii), floor(dd * pow(10,ii)))) {
sprintf (str,"%f", round(dd*pow(10,ii))/pow(10,ii));
match = 1;
break;
}
}
if ( match != 1 ) {
sprintf (str,"%f", round(dd*pow(10,max_len))/pow(10,max_len));
}
char *pp;
int count;
pp = strchr (str,'.');
if (pp != NULL) {
count = max_len;
while (count >= 0) {
count--;
if (*pp == '\0')
break;
pp++;
}
*pp-- = '\0';
while (*pp == '0')
*pp-- = '\0';
if (*pp == '.') {
*pp = '\0';
}
}
printf ("%s\n", str);
}
int main(int argc, char **argv)
{
printTruncatedDouble( -1.999, 2 ); // prints -2
printTruncatedDouble( -1.006, 2 ); // prints -1.01
printTruncatedDouble( -1.005, 2 ); // prints -1
printf("\n");
printTruncatedDouble( 1.005, 2 ); // prints 1 (should be 1.01?)
printTruncatedDouble( 1.006, 2 ); // prints 1.01
printTruncatedDouble( 1.999, 2 ); // prints 2
printf("\n");
printTruncatedDouble( -1.999, 3 ); // prints -1.999
printTruncatedDouble( -1.001, 3 ); // prints -1.001
printTruncatedDouble( -1.0005, 3 ); // prints -1.001 (shound be -1?)
printTruncatedDouble( -1.0004, 3 ); // prints -1
printf("\n");
printTruncatedDouble( 1.0004, 3 ); // prints 1
printTruncatedDouble( 1.0005, 3 ); // prints 1.001
printTruncatedDouble( 1.001, 3 ); // prints 1.001
printTruncatedDouble( 1.999, 3 ); // prints 1.999
printf("\n");
exit(0);
}
Here is my first try at an answer:
void
xprintfloat(char *format, float f)
{
char s[50];
char *p;
sprintf(s, format, f);
for(p=s; *p; ++p)
if('.' == *p) {
while(*++p);
while('0'==*--p) *p = '\0';
}
printf("%s", s);
}
Known bugs: Possible buffer overflow depending on format. If "." is present for other reason than %f wrong result might happen.
Slight variation on above:
Eliminates period for case (10000.0).
Breaks after first period is processed.
Code here:
void EliminateTrailingFloatZeros(char *iValue)
{
char *p = 0;
for(p=iValue; *p; ++p) {
if('.' == *p) {
while(*++p);
while('0'==*--p) *p = '\0';
if(*p == '.') *p = '\0';
break;
}
}
}
It still has potential for overflow, so be careful ;P
I would say you should use
printf("%.8g",value);
If you use "%.6g" you will not get desired output for some numbers like.32.230210 it should print 32.23021 but it prints 32.2302
Hit the same issue, double precision is 15 decimal, and float precision is 6 decimal, so I wrote to 2 functions for them separately
#include <stdio.h>
#include <math.h>
#include <string>
#include <string.h>
std::string doublecompactstring(double d)
{
char buf[128] = {0};
if (isnan(d))
return "NAN";
sprintf(buf, "%.15f", d);
// try to remove the trailing zeros
size_t ccLen = strlen(buf);
for(int i=(int)(ccLen -1);i>=0;i--)
{
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
return buf;
}
std::string floatcompactstring(float d)
{
char buf[128] = {0};
if (isnan(d))
return "NAN";
sprintf(buf, "%.6f", d);
// try to remove the trailing zeros
size_t ccLen = strlen(buf);
for(int i=(int)(ccLen -1);i>=0;i--)
{
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
return buf;
}
int main(int argc, const char* argv[])
{
double a = 0.000000000000001;
float b = 0.000001f;
printf("a: %s\n", doublecompactstring(a).c_str());
printf("b: %s\n", floatcompactstring(b).c_str());
return 0;
}
output is
a: 0.000000000000001
b: 0.000001
I needed that and the first answer from paxdiablo does the trick. But I was not needing truncating and the version below is maybe slightly faster?
Starting to search end of string (EOS) after the ".", only one placement of EOS.
//https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
//adapted from paxdiablo (removed truncating)
char StringForDouble[50];
char *PointerInString;
void PrintDouble (double number) {
sprintf(StringForDouble,"%.10f",number); // convert number to string
PointerInString=strchr(&StringForDouble[0],'.'); // find decimal point, if any
if(PointerInString!=NULL) {
PointerInString=strchr(&PointerInString[0],'\0'); // find end of string
do{
PointerInString--;
} while(PointerInString[0]=='0'); // remove trailing zeros
if (PointerInString[0]=='.') { // if all decimals were zeros, remove "."
PointerInString[0]='\0';
} else {
PointerInString[1]='\0'; //otherwise put EOS after the first non zero char
}
}
printf("%s",&StringForDouble[0]);
}
My idea is to calculate the required precision that would not result in trailing zeroes for a given double value and pass it to the "%1.*f" format in printf().
This can even be done as one-liner:
int main() {
double r=1234.56789;
int precision=3;
printf(L"%1.*f", prec(r, precision), r);
}
int prec(const double& r, int precision)
{
double rPos = (r < 0)? -r : r;
double nkd = fmod(rPos, 1.0); // 0..0.99999999
int i, ex10 = 1;
for (i = 0; i < precision; ++i)
ex10 *= 10;
int nki = (int)(nkd * ex10 + 0.5);
// "Eliminate" trailing zeroes
int requiredPrecision = precision;
for (; requiredPrecision && !(nki % 10); ) {
--requiredPrecision;
nki /= 10;
}
return requiredPrecision;
}
And here is another %g solution. You should always provide a format precision that is "wide enough" (default is only 6) and round the value. I think this is a nice way to do it:
double round(const double &value, const double& rounding) {
return rounding!=0 ? floor(value/rounding + 0.5)*rounding : value;
}
printf("%.12g" round(val, 0.001)); // prints up to 3 relevant digits
Your code rounds to three decimal places due to the ".3" before the f
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
Thus if you the second line rounded to two decimal places, you should change it to this:
printf("%1.3f", 359.01335);
printf("%1.2f", 359.00999);
That code will output your desired results:
359.013
359.01
*Note this is assuming you already have it printing on separate lines, if not then the following will prevent it from printing on the same line:
printf("%1.3f\n", 359.01335);
printf("%1.2f\n", 359.00999);
The Following program source code was my test for this answer
#include <cstdio>
int main()
{
printf("%1.3f\n", 359.01335);
printf("%1.2f\n", 359.00999);
while (true){}
return 0;
}

Resources