What's wrong with my printf output? - c

having trouble debugging the reason i'm getting a space between oct-nov and nov-dec. here is the code:
if (month == 1)
printf("jan");
if (month == 2)
printf("feb");
if (month == 3)
printf("march");
if (month == 4)
printf("apr");
if (month == 5)
printf("may");
if (month == 6)
printf("jun");
if (month == 7)
printf("jul");
if (month == 8)
printf("aug");
if (month == 9)
printf("sept");
if (month == 10)
printf("oct");
if (month == 11)
printf("nov");
if (month == 12)
printf("dec");
printf(" %c | %.1f | %.1f | %.1f | %.1f |\n", month, monthly->maxTemperature,
monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);
have tried changing the spacing as well but its always between those 2 months for some reason. Thanks!
edit:
it is part of this function :
void printMonthlyStatistic(int month,const struct MonthlyStatistic* monthly)
and is called in main program like this:
for(i=0;i<12;i++){
printMonthlyStatistic(i+1,&monthly[i])
my sample output:
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
jan | 9.8 | -26.2 | -7.8 | 55.3 |
feb | 7.5 | -23.3 | -8.6 | 33.1 |
march | 14.2 | -19.6 | -4.7 | 33.2 |
apr | 23.7 | -5.3 | 6.2 | 56.8 |
may | 33.0 | -0.6 | 13.9 | 62.7 |
jun | 32.1 | 8.0 | 19.7 | 69.7 |
jul | 34.9 | 12.6 | 22.2 | 181.8 |
aug | 31.5 | 11.0 | 20.9 | 69.2 |
sept | 34.1 | 5.0 | 16.1 | 69.0 |
oct
| 24.8 | -2.9 | 10.8 | 56.9 |
nov
| 16.0 | -12.8 | 2.1 | 36.2 |
dec
| 15.6 | -17.8 | -4.2 | 65.8 |

%c prints a character with the specified charcode, and if you use ASCII code, 10 is newline and 11 is vertical tab.
Also, you should use an array instead of writing those too-many ifs.
Try this:
static const char *month_names[] = {"jan", "feb", "march", "apr", "may", "jun", "jul", "aug", "sept", "oct", "nov", "dec"};
printf("%-11s| %.1f | %.1f | %.1f | %.1f |\n",
1 <= month && month <= 12 ? month_names[month - 1] : "", monthly->maxTemperature,
monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);

Your problem is the %c which prints a char. The ASCII value NewLine is 10 and the Vertical Tab is 11:

Related

Transforming a dataset in a more compact format (Stata)

initially I was dealing with a dataset that looked something like this:
+------+--------+-----------+-------+
| date | geo | variables | value |
+------+--------+-----------+-------+
| 1981 | Canada | var1 | # |
| 1982 | Canada | var1 | # |
| 1983 | Canada | var1 | # |
| ... | ... | ... | ... |
| 2015 | Canada | var2 | # |
| 1981 | Canada | var2 | # |
| 1982 | Canada | var2 | # |
| ... | ... | ... | ... |
| 2015 | Canada | var2 | # |
| 1981 | Quebec | var1 | # |
| 1982 | Quebec | var1 | # |
| 1983 | Quebec | var1 | # |
| ... | ... | ... | ... |
| 2015 | Quebec | var2 | # |
| 1981 | Quebec | var2 | # |
| 1982 | Quebec | var2 | # |
| ... | ... | ... | ... |
| 2015 | Quebec | var2 | # |
+------+--------+-----------+-------+
So I have 35 time periods, two countries and two variables. I would like to transform the table in Stata for it to look like this:
+------+--------+------+------+
| date | geo | var1 | var2 |
+------+--------+------+------+
| 1981 | Canada | # | # |
| 1982 | Canada | # | # |
| ... | ... | ... | ... |
| 2015 | Canada | # | # |
| 1981 | Quebec | # | # |
| 1982 | Quebec | # | # |
| ... | ... | ... | ... |
| 2015 | Quebec | # | # |
+------+--------+------+------+
However, I'm not having much success with this. I tried to separate the different observations into variables with the command:
separate value, by(variables) generate(var)
Which creates something like this:
+------+--------+------+------+
| date | geo | var1 | var2 |
+------+--------+------+------+
| 1981 | Canada | # | . |
| 1982 | Canada | # | . |
| ... | ... | ... | ... |
| 2015 | Canada | # | . |
| 1981 | Canada | . | # |
| 1982 | Canada | . | # |
| ... | ... | ... | ... |
| 2015 | Canada | . | # |
| 1981 | Quebec | # | . |
| 1982 | Quebec | # | . |
| ... | ... | ... | ... |
| 2015 | Quebec | # | . |
| 1981 | Quebec | . | # |
| 1982 | Quebec | . | # |
| ... | ... | ... | ... |
| 2015 | Quebec | . | # |
+------+--------+------+------+
Which contains a lot of useless missing values.
So, more specifically, I would like something to bring me directly to Table A to B (i.e. without using separate), or a solution to fix Table C into B.
Thanks a lot.
Without sample data, my answer will have to be untested. I think something like the following will get you started in the right direction.
reshape wide value, i(date geo) j(variables) string
Note that this assumes the contents of your variables variable are suitable for use as variable names. For example, a value of 1potato for variables would be a problem.
In any event,
help reshape
should be your first stop.
Added in response to comment: Here is some data I made up and a demonstration that reshape works for this data. Perhaps you can explain how this data differs from the real data. Your error message suggests that for some combination of date and geo, a particular value of variables occurs more than once.
. list, sepby(geo)
+----------------------------------+
| date geo variab~s value |
|----------------------------------|
1. | 1981 Canada var1 111 |
2. | 1982 Canada var1 211 |
3. | 1983 Canada var1 311 |
4. | 1981 Canada var2 112 |
5. | 1982 Canada var2 212 |
6. | 1983 Canada var2 312 |
|----------------------------------|
7. | 1981 Quebec var1 121 |
8. | 1982 Quebec var1 221 |
9. | 1983 Quebec var1 321 |
10. | 1981 Quebec var2 122 |
11. | 1982 Quebec var2 222 |
12. | 1983 Quebec var2 322 |
+----------------------------------+
. reshape wide value, i(geo date) j(variables) string
(note: j = var1 var2)
Data long -> wide
-----------------------------------------------------------------------------
Number of obs. 12 -> 6
Number of variables 4 -> 4
j variable (2 values) variables -> (dropped)
xij variables:
value -> valuevar1 valuevar2
-----------------------------------------------------------------------------
. rename (value*) (*)
. list, sepby(geo)
+-----------------------------+
| date geo var1 var2 |
|-----------------------------|
1. | 1981 Canada 111 112 |
2. | 1982 Canada 211 212 |
3. | 1983 Canada 311 312 |
|-----------------------------|
4. | 1981 Quebec 121 122 |
5. | 1982 Quebec 221 222 |
6. | 1983 Quebec 321 322 |
+-----------------------------+
.

Powerpivot 2016 measure using DAX to sum an array

I want to sum the 7 preceding values of a row as a measure like so:
| Wk_number | Value A | Measure | Array |
-------------------------------------------
| 01 | 1 | N/A# | N/A# |
| 02 | 1 | 1 | {01} |
| 03 | 10 | 2 | {01-02} |
| 04 | 3 | 12 | {01-03} |
| 05 | 5 | 15 | {01-04} |
| 06 | 10 | 20 | {01-05} |
| 07 | 1 | 30 | {01-06} |
| 08 | 4 | 31 | {01-07} |
| 09 | -10 | 34 | {02-08} |
| 10 | 3 | 26 | {03-09} |
| 11 | 2 | 18 | {04-10} |
etc...
I added the array column just to clarify the example how of the sum is comprised, notice that from wk09 it's not simply a running total.
How to do this using DAX statements?
Two ways to do this: you can either create a calculated column, or a measure.
For the column:
=CALCULATE(SUM([Value A]),FILTER(Table,Table[Wk_number]<EARLIER(Table[Wk_number]) && Table[Wk_number] >= (EARLIER(Table[Wk_number])-7)))
For the measure, it's a very similar formula but instead of using EARLIER(), we use MAX():
=CALCULATE(SUM([Value A]),FILTER(ALL(Table3),Table3[Wk_number]<MAX(Table3[Wk_number]) && Table3[Wk_number] >= (MAX(Table3[Wk_number])-7)))
Below is a screenshot of the results. A few of the numbers in your example table seem to be off based on the math:

Why is my printf output crooked?

I want all my lines to line up correctly, but for some reason when i print it out it looks crooked, like this:
Weather summary for 2013
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
| January| 9.8 | -26.2 | -7.8 | 55.3 |
| February| 7.5 | -23.3 | -8.6 | 33.1 |
| March| 14.2 | -19.6 | -4.7 | 33.2 |
| April| 23.7 | -5.3 | 6.2 | 56.8 |
| May| 33.0 | -0.6 | 13.9 | 62.7 |
| June| 32.1 | 8.0 | 19.7 | 69.7 |
| July| 34.9 | 12.6 | 22.2 | 181.8 |
| August| 31.5 | 11.0 | 20.9 | 69.2 |
| September| 34.1 | 5.0 | 16.1 | 69.0 |
| October| 24.8 | -2.9 | 10.8 | 56.9 |
| November| 16.0 | -12.8 | 2.1 | 36.2 |
| December| 15.6 | -17.8 | -4.2 | 65.8 |
my code for the printf call:
printf("| %10s| %-4.1f | %-4.1f | %-4.1f | %-4.1f |\n",month_names[month - 1] ,
monthly->maxTemperature,monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);
Thanks!
For this kind of formatted output, all you need is a rough estimation of the width of each field, then let printf do all the formatting, instead of counting the spaces then coming up with something like %4.1f..
For example in this case, start with the header, give a rough estimate of the width of each header fields:
printf( "|%-20s|%-10s|%-10s|%-10s|%-10s|\n", "Month", "High", "Low", "Avg", "Precip" );
Then for the following rows, use the same width, just replace %s with %f for float numbers. You can manipulate how many position after the decimal point.
printf( "|%-20s|%-10.1f|%-10.1f|%-10.1f|%-10.1f|\n", ...
Since you are using -4.1f as your printf specifier, you will always get 1 space after the decimal point, so 4 total spaces isn't enough for the negative numbers, and printf is adding an extra space in the output for you. So, you will need to use -5.1f to get enough space for one decimal point and the - sign. So, if you end up with a number like -123.4, you won't get proper alignment again.

How to convert month(int) into month name (string)

I'm having a problem with a function i'm working on. I am able to get the proper data, just not print out the names of the month as well.
sample output i'm getting:
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
1 | 9.8 | -26.2 | -7.8 | 55.3 |
2 | 7.5 | -23.3 | -8.6 | 33.1 |
3 | 14.2 | -19.6 | -4.7 | 33.2 |
4 | 23.7 | -5.3 | 6.2 | 56.8 |
5 | 33.0 | -0.6 | 13.9 | 62.7 |
6 | 32.1 | 8.0 | 19.7 | 69.7 |
7 | 34.9 | 12.6 | 22.2 | 181.8 |
8 | 31.5 | 11.0 | 20.9 | 69.2 |
9 | 34.1 | 5.0 | 16.1 | 69.0 |
10 | 24.8 | -2.9 | 10.8 | 56.9 |
11 | 16.0 | -12.8 | 2.1 | 36.2 |
12 | 15.6 | -17.8 | -4.2 | 65.8
I want to conver digits 1-12 to there proper month names. Ie: 1 = January.
void printMonthlyStatistic(int month,const struct MonthlyStatistic* monthly)
is what the function looks like
for(i=0;i<12;i++){
printMonthlyStatistic(i+1,&monthly[i])
and is called in main as such.
Any help onto where to look for the proper method to complete this would be great. Thanks!
You should use an array to store the name of the month, like:
const char * months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
You can get the name of the month easily, for example, if index = 1, then
months[index -1]
will give you the first month name: January.
The following code:
for (int i = 0; i < 12; ++i) {
printf("%s ", months[i]);
}
will output:
January February March April May June July August September October
November December
You can maintain Month Array of String like
char months_names[12] = {Jan, Feb, Mar, Apr, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
You can Just paas integer number month to array for getting String value
months_names["Integrer Value"] You will get String name of month.

How to make a SQL "IF-THEN-ELSE" statement

I've seen other questions about SQL If-then-else stuff, but I'm not seeing how to relate it to what I'm trying to do. I've been using SQL for about a year now but only basic stuff and never this.
If I have a SQL table that looks like this
| Name | Version | Category | Value | Number |
|:-----:|:-------:|:--------:|:-----:|:------:|
| File1 | 1.0 | Time | 123 | 1 |
| File1 | 1.0 | Size | 456 | 1 |
| File1 | 1.0 | Final | 789 | 1 |
| File2 | 1.0 | Time | 312 | 1 |
| File2 | 1.0 | Size | 645 | 1 |
| File2 | 1.0 | Final | 978 | 1 |
| File3 | 1.0 | Time | 741 | 1 |
| File3 | 1.0 | Size | 852 | 1 |
| File3 | 1.0 | Final | 963 | 1 |
| File1 | 1.1 | Time | 369 | 2 |
| File1 | 1.1 | Size | 258 | 2 |
| File1 | 1.1 | Final | 147 | 2 |
| File2 | 1.1 | Time | 741 | 2 |
| File2 | 1.1 | Size | 734 | 2 |
| File2 | 1.1 | Final | 942 | 2 |
| File3 | 1.1 | Time | 997 | 2 |
| File3 | 1.1 | Size | 997 | 2 |
| File3 | 1.1 | Final | 985 | 2 |
How can I write a SQL IF, ELSE statement that creates a new column called "Replication" that follows this rule:
A = B + 1 when x = 1
else
A = B
where A = the number we will use for the next Number
B = Max(Number)
x = Replication count (this is the number of times that a loop is executed. x=i)
The results table will look like this:
| Name | Version | Category | Value | Number | Replication |
|:-----:|:-------:|:--------:|:-----:|:------:|:-----------:|
| File1 | 1.0 | Time | 123 | 1 | 1 |
| File1 | 1.0 | Size | 456 | 1 | 1 |
| File1 | 1.0 | Final | 789 | 1 | 1 |
| File2 | 1.0 | Time | 312 | 1 | 1 |
| File2 | 1.0 | Size | 645 | 1 | 1 |
| File2 | 1.0 | Final | 978 | 1 | 1 |
| File1 | 1.0 | Time | 369 | 1 | 2 |
| File1 | 1.0 | Size | 258 | 1 | 2 |
| File1 | 1.0 | Final | 147 | 1 | 2 |
| File2 | 1.0 | Time | 741 | 1 | 2 |
| File2 | 1.0 | Size | 734 | 1 | 2 |
| File2 | 1.0 | Final | 942 | 1 | 2 |
| File1 | 1.1 | Time | 997 | 2 | 1 |
| File1 | 1.1 | Size | 997 | 2 | 1 |
| File1 | 1.1 | Final | 985 | 2 | 1 |
| File2 | 1.1 | Time | 438 | 2 | 1 |
| File2 | 1.1 | Size | 735 | 2 | 1 |
| File2 | 1.1 | Final | 768 | 2 | 1 |
| File1 | 1.1 | Time | 786 | 2 | 2 |
| File1 | 1.1 | Size | 486 | 2 | 2 |
| File1 | 1.1 | Final | 135 | 2 | 2 |
| File2 | 1.1 | Time | 379 | 2 | 2 |
| File2 | 1.1 | Size | 943 | 2 | 2 |
| File2 | 1.1 | Final | 735 | 2 | 2 |
EDIT: Based on the answer by Sean Lange, this is my 2nd attempt at a solution:
SELECT COALESCE(MAX)(Number) + CASE WHEN Replication = 1 then 1 else 0, 1) FROM Table
The COALESCE is in there for when there is no value yet in the Number column.
The IF/Else construct is used to control flow of statements in t-sql. You want a case expression, which is used to conditionally return values in a column.
https://msdn.microsoft.com/en-us/library/ms181765.aspx
Yours would be something like:
case when x = 1 then A else B end as A
As SeanLange pointed out in this case it would be better to use an CASE/WHEN but to illustrate how to use If\ELSE the way to do it in sql is like this:
if x = 1
BEGIN
---Do something
END
ELSE
BEGIN
--Do something else
END
I would say the best way to know the difference and when to use which is if you are writing a query and want a different field to appear based on a certain condition, use case/when. If a certain condition will cause a series of steps to happen then use if/else

Resources