Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #164058 > unrolled thread
| Started by | Manu Raju <MR@invalid.invalid> |
|---|---|
| First post | 2021-12-25 01:00 +0000 |
| Last post | 2021-12-29 15:21 +0000 |
| Articles | 20 on this page of 113 — 19 participants |
Back to article view | Back to comp.lang.c
Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-25 01:00 +0000
Re: Can this program be improved? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-12-24 21:44 -0800
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2021-12-25 12:56 +0100
Re: Can this program be improved? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-25 11:13 -0800
Re: Can this program be improved? Manfred <noname@add.invalid> - 2021-12-25 23:50 +0100
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 18:52 +0000
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-26 19:22 +0000
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 21:30 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-26 22:02 +0000
Re: Can this program be improved? Richard Damon <Richard@Damon-Family.org> - 2021-12-26 18:24 -0500
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-27 00:47 +0000
Re: Can this program be improved? Guillaume <message@bottle.org> - 2021-12-29 17:52 +0100
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-29 17:49 +0000
Re: Can this program be improved? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-12-29 11:33 -0800
Re: Can this program be improved? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-29 22:45 -0500
Re: Can this program be improved? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-12-30 00:35 -0800
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2021-12-30 10:19 +0100
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-01 18:19 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-01 19:33 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-29 14:37 -0800
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-29 23:09 +0000
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2021-12-29 23:54 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-29 16:11 -0800
Re: Can this program be improved? Kaz Kylheku <480-992-1380@kylheku.com> - 2021-12-30 00:34 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-30 12:49 +0000
Re: Can this program be improved? Kaz Kylheku <480-992-1380@kylheku.com> - 2021-12-30 21:04 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-31 02:13 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-29 16:09 -0800
Re: Can this program be improved? Kaz Kylheku <480-992-1380@kylheku.com> - 2021-12-30 00:59 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-29 17:48 -0800
Re: Can this program be improved? Kaz Kylheku <480-992-1380@kylheku.com> - 2021-12-30 20:47 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-30 01:06 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-12-30 04:48 -0800
Re: Can this program be improved? Manfred <noname@add.invalid> - 2021-12-30 18:16 +0100
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-31 02:20 +0000
Re: Can this program be improved? Manfred <noname@add.invalid> - 2021-12-31 18:25 +0100
Re: Can this program be improved? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-31 18:13 -0500
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-31 23:59 +0000
Re: Can this program be improved? "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2021-12-31 16:20 -0800
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-31 16:35 -0800
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-01 00:53 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-31 20:22 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-12-31 22:04 -0800
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-01 14:59 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-02 17:22 -0800
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-02 20:49 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 03:09 -0800
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2022-01-03 16:22 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-03 14:42 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 14:52 -0800
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-03 22:58 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 04:27 -0800
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-04 13:39 +0000
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2022-01-04 00:18 +0100
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-03 15:24 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 15:43 -0800
Re: Can this program be improved? Öö Tiib <ootiib@hot.ee> - 2022-01-03 21:19 -0800
Re: Can this program be improved? Mateusz Viste <mateusz@xyz.invalid> - 2022-01-04 09:23 +0100
Re: Can this program be improved? Guillaume <message@bottle.org> - 2022-01-04 18:18 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 10:35 -0800
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-04 14:07 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 15:11 -0800
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-04 15:47 -0800
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 18:30 -0800
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2022-01-04 23:46 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-04 18:41 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 10:52 -0800
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2022-01-04 19:00 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 11:15 -0800
Re: Can this program be improved? Guillaume <message@bottle.org> - 2022-01-04 21:57 +0100
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-04 21:02 +0000
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2022-01-04 21:38 +0000
Re: Can this program be improved? Manfred <noname@add.invalid> - 2022-01-04 23:01 +0100
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2022-01-04 09:31 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 01:30 -0800
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2022-01-04 14:55 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-04 06:21 -0800
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2022-01-04 16:49 +0100
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-04 15:56 +0000
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-04 15:03 +0000
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-03 22:54 +0000
Re: Can this program be improved? Mateusz Viste <mateusz@xyz.invalid> - 2022-01-03 09:22 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 03:30 -0800
Re: Can this program be improved? David Brown <david.brown@hesbynett.no> - 2022-01-03 17:22 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 08:48 -0800
Re: Can this program be improved? Mateusz Viste <mateusz@xyz.invalid> - 2022-01-03 18:42 +0100
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-03 17:59 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 11:09 -0800
Re: Can this program be improved? Mateusz Viste <mateusz@xyz.invalid> - 2022-01-03 20:32 +0100
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-01-03 11:58 -0800
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2022-01-03 18:13 +0000
Re: Can this program be improved? gazelle@shell.xmission.com (Kenny McCormack) - 2022-01-03 20:05 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2022-01-01 16:53 +0000
Re: Can this program be improved? Kaz Kylheku <480-992-1380@kylheku.com> - 2021-12-30 00:29 +0000
Re: Can this program be improved? Bart <bc@freeuk.com> - 2021-12-25 12:47 +0000
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 18:56 +0000
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-25 17:38 +0000
Re: Can this program be improved? Öö Tiib <ootiib@hot.ee> - 2021-12-25 10:58 -0800
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-25 19:16 +0000
Re: Can this program be improved? Öö Tiib <ootiib@hot.ee> - 2021-12-25 11:25 -0800
Re: Can this program be improved? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-12-25 15:01 -0800
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-25 23:09 +0000
Re: Can this program be improved? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-12-25 20:56 -0800
Re: Can this program be improved? scott@slp53.sl.home (Scott Lurndal) - 2021-12-25 19:30 +0000
Re: Can this program be improved? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-25 15:50 -0800
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 19:02 +0000
Re: Can this program be improved? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-12-25 11:53 -0800
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 19:00 +0000
Re: Can this program be improved? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-25 11:22 -0800
Re: Can this program be improved? Manu Raju <MR@invalid.invalid> - 2021-12-26 19:01 +0000
Re: Can this program be improved? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-12-25 13:27 -0800
Re: Can this program be improved? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-12-25 16:06 -0800
Re: Can this program be improved? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-12-29 15:21 +0000
Page 1 of 6 [1] 2 3 4 5 6 Next page →
| From | Manu Raju <MR@invalid.invalid> |
|---|---|
| Date | 2021-12-25 01:00 +0000 |
| Subject | Can this program be improved? |
| Message-ID | <sq63mi$gom$1@dont-email.me> |
>
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <math.h>
>
> int main()
> {
> float P = 100000; // Loan Amount
> float r = 7.5; // Advertised Interest Rate
> int n = 12; // Loan Period
> float payBack = (P * r / 1200 * pow(1 + r / 1200, n)) / (pow((1 +
> r / 1200), n) - 1);
> float Opening = P; // Opening Balance
> float closing = 0; // Closing Balance
> float interest = 0;
> float Total = 0;
> float repaid = 0;
>
> printf("\nMonthly payment is: %.2f\n", payBack);
>
> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
> "Interest", "Total", "Repayment", "Balance");
>
> for (int i = 1; i <= n; i++)
> {
> for (int j = 0; j <= n; j++)
> {
> interest = Opening * r / 1200;
> Total = Opening + interest;
> repaid = payBack;
> closing = Total - payBack;
> }
> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
> Opening, interest, Total, repaid, closing);
> Opening = closing;
> }
> return 0;
> }
>
> /*
> * Output should be:
> Monthly payment is: 8675.71
> Month Beginning Interest Total Repayment Balance
> 1 100000 625 100625 8676 91949
> 2 91949 575 92524 8676 83848
> 3 83848 524 84372 8676 75697
> 4 75697 473 76170 8676 67494
> 5 67494 422 67916 8676 59240
> 6 59240 370 59610 8676 50935
> 7 50935 318 51253 8676 42577
> 8 42577 266 42843 8676 34168
> 9 34168 214 34381 8676 25706
> 10 25706 161 25866 8676 17190
> 11 17190 107 17298 8676 8622
> 12 8622 54 8676 8676 0
>
> */
>
>
>
>
>
[toc] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2021-12-24 21:44 -0800 |
| Message-ID | <sq6b3t$ce5$1@dont-email.me> |
| In reply to | #164058 |
On 12/24/2021 5:00 PM, Manu Raju wrote:
>>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <math.h>
>>
>> int main()
>> {
>> float P = 100000; // Loan Amount
>> float r = 7.5; // Advertised Interest Rate
>> int n = 12; // Loan Period
>> float payBack = (P * r / 1200 * pow(1 + r / 1200, n)) / (pow((1 +
>> r / 1200), n) - 1);
>> float Opening = P; // Opening Balance
>> float closing = 0; // Closing Balance
>> float interest = 0;
>> float Total = 0;
>> float repaid = 0;
>>
>> printf("\nMonthly payment is: %.2f\n", payBack);
>>
>> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
>> "Interest", "Total", "Repayment", "Balance");
>>
>> for (int i = 1; i <= n; i++)
>> {
>> for (int j = 0; j <= n; j++)
>> {
>> interest = Opening * r / 1200;
>> Total = Opening + interest;
>> repaid = payBack;
>> closing = Total - payBack;
>> }
>> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
>> Opening, interest, Total, repaid, closing);
>> Opening = closing;
>> }
>> return 0;
>> }
Certainly.
1. int main(void)
2. Stop using `float` for local variables. "Default" floating-point type
in C is `double`. Everything else is used only if you have a good reason
to do that. In this case you don't.
3. Stop using "regular" floating point types for representing monetary
quantities. They are not good for that purpose.
4. It appears that you are actually trying to use `float` to represent
_integer_ quantities (judging by your `printf`). Why?
5. Stop using `pow` for calculating integer powers. You don't really
need `<math.h>` here.
6. Stop piling up all variable declarations at the beginning of the
function. Declare variables as locally as possible.
7. Stop using dummy initializers for your variables. It is better to
leave them uninitialized than initialize them to dummy zeros. This point
is actually connected to the previous one: once you start declaring
variables as locally as possible, you'll normally have a meaningful
initializers for them at the point of declaration.
8. What's going on with capitalization in your variables names?
`Opening`, `closing`, `interest`, `Total`? Is this a convention of some
sort?
9. "Magical constants"? What on Earth is `1200`?
10. Repetitive subexpressions, like `1 + r / 1200` (some explicit, some
slightly obfuscated) are probably a matter of style.... But anyway: DRY
- do not repeat yourself.
--
Best regards,
Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-12-25 12:56 +0100 |
| Message-ID | <sq70ss$hlh$1@dont-email.me> |
| In reply to | #164059 |
On 25/12/2021 06:44, Andrey Tarasevich wrote: > > Certainly. > > 1. int main(void) > > 2. Stop using `float` for local variables. "Default" floating-point type > in C is `double`. Everything else is used only if you have a good reason > to do that. In this case you don't. > > 3. Stop using "regular" floating point types for representing monetary > quantities. They are not good for that purpose. > > 4. It appears that you are actually trying to use `float` to represent > _integer_ quantities (judging by your `printf`). Why? > > 5. Stop using `pow` for calculating integer powers. You don't really > need `<math.h>` here. > > 6. Stop piling up all variable declarations at the beginning of the > function. Declare variables as locally as possible. > > 7. Stop using dummy initializers for your variables. It is better to > leave them uninitialized than initialize them to dummy zeros. This point > is actually connected to the previous one: once you start declaring > variables as locally as possible, you'll normally have a meaningful > initializers for them at the point of declaration. > > 8. What's going on with capitalization in your variables names? > `Opening`, `closing`, `interest`, `Total`? Is this a convention of some > sort? > > 9. "Magical constants"? What on Earth is `1200`? > > 10. Repetitive subexpressions, like `1 + r / 1200` (some explicit, some > slightly obfuscated) are probably a matter of style.... But anyway: DRY > - do not repeat yourself. > That's a good list. Let me add: 11. Be very suspicious of short variable names with a comment attached. It /might/ be the best choice, because of the way the variable is used or how it matches some external information (like a mathematical formula). But often it is better to give the variable a more complete name. (As a rule of thumb, the smaller the scope, the shorter the variable name you can get away with.) 12. Be clear in your units - perhaps also including them in names or even type information (though that is not common in C). Make it clear which variables are money, percentages, monthly rates, annual rates, etc. 13. Any variables that are fixed at initialisation and not changed should be declared with "const". It makes code clearer and lets the compiler catch some kinds of mistakes. 14. It looks like you are mixing up 12 years loan period and 12 months per year, using the same rather anonymous variable "n" for the purpose. (Don't take this long list as a sign that your code is terrible. It's not bad, and I'm sure we've all seen far worse. But these are all tips for ways to improve it and get in good coding habits early.)
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-12-25 11:13 -0800 |
| Message-ID | <868rw81or6.fsf@linuxsc.com> |
| In reply to | #164059 |
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
> On 12/24/2021 5:00 PM, Manu Raju wrote:
>
>> [revised to repair white space]
>>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <math.h>
>>
>> int main()
>> {
>> float P = 100000; // Loan Amount
>> float r = 7.5; // Advertised Interest Rate
>> int n = 12; // Loan Period
>> float payBack = (P * r / 1200 * pow(1 + r / 1200, n))
>> / (pow((1 + r / 1200), n) - 1);
>> float Opening = P; // Opening Balance
>> float closing = 0; // Closing Balance
>> float interest = 0;
>> float Total = 0;
>> float repaid = 0;
>>
>> printf("\nMonthly payment is: %.2f\n", payBack);
>>
>> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
>> "Interest", "Total", "Repayment", "Balance");
>>
>> for (int i = 1; i <= n; i++)
>> {
>> for (int j = 0; j <= n; j++)
>> {
>> interest = Opening * r / 1200;
>> Total = Opening + interest;
>> repaid = payBack;
>> closing = Total - payBack;
>> }
>> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
>> Opening, interest, Total, repaid, closing);
>> Opening = closing;
>> }
>> return 0;
>> }
>
> Certainly.
>
> 1. int main(void)
Check.
> 2. Stop using `float` for local variables. "Default" floating-point
> type in C is `double`. Everything else is used only if you have a
> good reason to do that. In this case you don't.
Check.
> 3. Stop using "regular" floating point types for representing
> monetary quantities. They are not good for that purpose.
For this level of programming I think floating point is okay. A
problem that is important is the program makes no effort to round
(to the nearest cent, for example), so the calculation gives
funny results typical of calculations done with floating point.
But that problem can be addressed without throwing out floating
point altogether.
> 4. It appears that you are actually trying to use `float` to
> represent _integer_ quantities (judging by your `printf`). Why?
To me that just looks like what the print formats are, not what
the kinds of quantities are.
> 5. Stop using `pow` for calculating integer powers. You don't
> really need `<math.h>` here.
I have to vote against this comment. Using pow() makes it
obvious what is being done, the exponent being integral
notwithstanding.
> 6. Stop piling up all variable declarations at the beginning of
> the function. Declare variables as locally as possible.
Good advice here I would say, but this rule is a point of style
with differing viewpoints.
> 7. Stop using dummy initializers for your variables. It is better
> to leave them uninitialized than initialize them to dummy zeros.
> This point is actually connected to the previous one: once you
> start declaring variables as locally as possible, you'll normally
> have a meaningful initializers for them at the point of declaration.
Check.
> 8. What's going on with capitalization in your variables names?
> Opening`, `closing`, `interest`, `Total`? Is this a convention of
> some sort?
Check.
> 9. "Magical constants"? What on Earth is `1200`?
Check. However I think it should be added that the "magicness"
of the constant(s) can be addressed by rephrasing the expressions
where they are used, without necessarily taking the constants
out of those expressions.
> 10. Repetitive subexpressions, like `1 + r / 1200` (some explicit,
> some slightly obfuscated) are probably a matter of style.... But
> anyway: DRY - do not repeat yourself.
More significant here, I think, is that defining a variable with
the value of this expression offers an opportunity to give some
sort of descriptive name to the quantity.
Two additional points:
The #include <stdlib.h> can be removed.
The inner loop (with 'j' as the index variable) does the same
calculation over and over again. There is no reason to make
that a loop - just write the body.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-12-25 23:50 +0100 |
| Message-ID | <sq877f$dof$1@gioia.aioe.org> |
| In reply to | #164059 |
On 12/25/2021 6:44 AM, Andrey Tarasevich wrote:
> 6. Stop piling up all variable declarations at the beginning of the
> function. Declare variables as locally as possible.
Put this way, this is questionable advice, IMO.
Experienced programmers may have your same opinion, but some others,
equally experienced, may label that same programming style as sloppy -
I've seen some myself.
In order to turn this opinion into good advice, I think there is more to
add to it:
1) Functions should perform simple, well defined tasks, which implies
that complex tasks should be split into multiple functions. After you do
this, then it becomes natural that you don't have "piles" of local
variables, and you may well have the variables you need at the beginning
of the function and still be "local".
2) Make good use of language constructs to keep counters, indexes etc.
local: for example, instead of declaring a generic counter "n" at the
beginning of the function and reuse it multiple times, prefer the following:
for (int n = 0; n < COUNT; ++n)
{
/* ... */
}
and thus have multiple "for" (and friends) constructs each with its own
counter.
3) If in the function body you have a code section that performs some
specific operation that needs its local variables, you may use a local
scope for it, and declare its variables inside it (check point 1 above
as well):
int myfunction(void)
{
/* ... */
{
int myvar = 42;
/* ... */
}
/* ... */
}
Obviously, the body of language constructs like "if", "for", "while",
"do" make natural local scopes that are good candidates for this purpose.
4) For algorithmic parameters that may affect the entire task, (e.g.
number of months in a year), you may well have a "const" variable at the
beginning of the function. "static const" at the beginning of the source
file is also an option, as well as many others.
>
> 7. Stop using dummy initializers for your variables. It is better to
> leave them uninitialized than initialize them to dummy zeros. This point
> is actually connected to the previous one: once you start declaring
> variables as locally as possible, you'll normally have a meaningful
> initializers for them at the point of declaration.
This is tricky. One of the worst bugs I have ever encountered was
"strlen" being called on an uninitialized string buffer.
I believe the best option is to initialize variables with meaningful
values, which leads to locality, as you say, but with my notes above.
However, as a last resort, it is probably better to leave them
uninitialized, rather than dummy zeros, *if* you have a decent compiler
that will spot its use before assignment.
[toc] | [prev] | [next] | [standalone]
| From | Manu Raju <MR@invalid.invalid> |
|---|---|
| Date | 2021-12-26 18:52 +0000 |
| Message-ID | <sqae28$g83$1@dont-email.me> |
| In reply to | #164059 |
On 25/12/2021 05:44, Andrey Tarasevich wrote:
> On 12/24/2021 5:00 PM, Manu Raju wrote:
>>>
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>> #include <math.h>
>>>
>>> int main()
>>> {
>>> float P = 100000; // Loan Amount
>>> float r = 7.5; // Advertised Interest Rate
>>> int n = 12; // Loan Period
>>> float payBack = (P * r / 1200 * pow(1 + r / 1200, n)) / (pow((1 +
>>> r / 1200), n) - 1);
>>> float Opening = P; // Opening Balance
>>> float closing = 0; // Closing Balance
>>> float interest = 0;
>>> float Total = 0;
>>> float repaid = 0;
>>>
>>> printf("\nMonthly payment is: %.2f\n", payBack);
>>>
>>> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
>>> "Interest", "Total", "Repayment", "Balance");
>>>
>>> for (int i = 1; i <= n; i++)
>>> {
>>> for (int j = 0; j <= n; j++)
>>> {
>>> interest = Opening * r / 1200;
>>> Total = Opening + interest;
>>> repaid = payBack;
>>> closing = Total - payBack;
>>> }
>>> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
>>> Opening, interest, Total, repaid, closing);
>>> Opening = closing;
>>> }
>>> return 0;
>>> }
>
>
> 9. "Magical constants"? What on Earth is `1200`?
It is just a figure 12 * 100. You first need to convert percentage into
decimals by dividing by 100; Then you need to divide the number again by
12 to give monthly rate. Interest rate is normally annual rate. Hope
this explains the magic number.
X-Mozilla-Status: 0811
X-Mozilla-Status2: 00000000
X-Mozilla-Keys:
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-12-26 19:22 +0000 |
| Message-ID | <sqafdf$qtd$1@dont-email.me> |
| In reply to | #164082 |
On Sun, 26 Dec 2021 18:52:14 +0000, Manu Raju wrote:
> On 25/12/2021 05:44, Andrey Tarasevich wrote:
>> On 12/24/2021 5:00 PM, Manu Raju wrote:
>>>>
>>>> #include <stdio.h>
>>>> #include <stdlib.h>
>>>> #include <math.h>
>>>>
>>>> int main()
>>>> {
>>>> float P = 100000; // Loan Amount
>>>> float r = 7.5; // Advertised Interest Rate
>>>> int n = 12; // Loan Period
>>>> float payBack = (P * r / 1200 * pow(1 + r / 1200, n)) / (pow((1 +
>>>> r / 1200), n) - 1);
>>>> float Opening = P; // Opening Balance
>>>> float closing = 0; // Closing Balance
>>>> float interest = 0;
>>>> float Total = 0;
>>>> float repaid = 0;
>>>>
>>>> printf("\nMonthly payment is: %.2f\n", payBack);
>>>>
>>>> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
>>>> "Interest", "Total", "Repayment", "Balance");
>>>>
>>>> for (int i = 1; i <= n; i++)
>>>> {
>>>> for (int j = 0; j <= n; j++)
>>>> {
>>>> interest = Opening * r / 1200;
>>>> Total = Opening + interest;
>>>> repaid = payBack;
>>>> closing = Total - payBack;
>>>> }
>>>> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
>>>> Opening, interest, Total, repaid, closing);
>>>> Opening = closing;
>>>> }
>>>> return 0;
>>>> }
>>
>>
>> 9. "Magical constants"? What on Earth is `1200`?
>
>
> It is just a figure 12 * 100. You first need to convert percentage into
> decimals by dividing by 100; Then you need to divide the number again by
> 12 to give monthly rate. Interest rate is normally annual rate. Hope
> this explains the magic number.
Well, you've explained it to us, but not to whomever will read your program next.
A good part of the art of programming is writing readable code; readable to you,
readable to you in 5 years from now, readable to the programmer that has to make
the next change to it, readable to the programmer who has to fix the bug in it.
Your use of 1200 is confusing, unless you already know that it facilitates the
conversion of a yearly interest rate expressed as a percent into a monthly
interest rate expressed as a decimal. It is worth noting that, should you
change the loan period expressed in P, you would /also/ have to change this
1200 "magic number" appropriately (or is P a "loan period in years"? if so,
then I believe that your interest calculations are wrong.)
--
Lew Pitcher
"In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Manu Raju <MR@invalid.invalid> |
|---|---|
| Date | 2021-12-26 21:30 +0000 |
| Message-ID | <sqanf8$9gs$1@dont-email.me> |
| In reply to | #164087 |
On 26/12/2021 19:22, Lew Pitcher wrote:
>
>
> Your use of 1200 is confusing, unless you already know that it facilitates the
> conversion of a yearly interest rate expressed as a percent into a monthly
> interest rate expressed as a decimal. It is worth noting that, should you
> change the loan period expressed in P, you would /also/ have to change this
> 1200 "magic number" appropriately (or is P a "loan period in years"? if so,
> then I believe that your interest calculations are wrong.)
>
>
The figure of 1200 will NEVER change. There will always be 12 months in
a year and we will always have to divide by 100 to express percentage as
decimals.
The interest rate can change and period (I used n) can also change. I used (n = 12) in my program to fit the table for people to see but
you can have 360 (30 years * 12). The program will still work.
Tim did a very good job to write a function. Did you see it? It is here.
<===========================================================================================>
void show_payment_table(double amount, double yearly_percentage_rate,
int months)
{
double const monthly_rate = yearly_percentage_rate / 100 / 12;
double const compounded = pow(1 + monthly_rate, months);
double const adjustment = compounded / (compounded - 1);
double const payment = amount * monthly_rate * adjustment;
double balance = amount;
printf("\nMonthly payment is: %.2f\n", payment);
printf("%10s %14s %13s %10s %14s %12s\n",
"Month", "Beginning", "Interest", "Total", "Repayment",
"Balance");
for (int i = 1; i <= months; i++)
{
double const interest = balance * monthly_rate;
double const owing = balance + interest;
double const remaining = owing - payment;
printf("%10d %14.2f %13.2f %10.2f %14.2f %12.2f\n",
i, balance, interest, owing, payment, remaining);
balance = remaining;
}
<===========================================================================================>
Now in the main function you just need to use it like so:
<===========================================================================================>
show_payment_table(250000, 5.0, 360);
<===========================================================================================>
This program is part of a big project where users will insert their
figures to calculate their repayments. all they need to enter will be
the Loan Amount, Interest Rate, and the Duration of the Loan. the
program will give them the schedule they can base their decision on. The
Windows Form/WPF will be used for these entries and "ASP.Net/MVC" for
the web site.
Best regards and have a very Happy New Year.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-12-26 22:02 +0000 |
| Message-ID | <sqaoqb$hd5$1@dont-email.me> |
| In reply to | #164090 |
On 26/12/2021 21:30, Manu Raju wrote: > On 26/12/2021 19:22, Lew Pitcher wrote: >> >> >> Your use of 1200 is confusing, unless you already know that it facilitates the >> conversion of a yearly interest rate expressed as a percent into a monthly >> interest rate expressed as a decimal. It is worth noting that, should you >> change the loan period expressed in P, you would /also/ have to change this >> 1200 "magic number" appropriately (or is P a "loan period in years"? if so, >> then I believe that your interest calculations are wrong.) >> >> > > The figure of 1200 will NEVER change. There will always be 12 months in > a year and we will always have to divide by 100 to express percentage as > decimals. Imagine this is part of a bigger program, and the constant 1200 also occurs elsewhere with a different meaning. /That/ 1200 might need to change, but now you don't know which 1200s are relevant.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2021-12-26 18:24 -0500 |
| Message-ID | <uQ6yJ.190873$3q9.17755@fx47.iad> |
| In reply to | #164090 |
On 12/26/21 4:30 PM, Manu Raju wrote: > The figure of 1200 will NEVER change. There will always be 12 months in > a year and we will always have to divide by 100 to express percentage as > decimals. Actually that is a BIG assumption, that assumes that the ONLY payment schedule is monthly. Some people take out loans with Semi-Monthly (or B-Weekly) payment schedules to pay things off a bit faster it that is how they get paid. You might even choose weekly, or some are paid annually or things in between. All these change the 1200 to something else, to something like 100 * payments_per_year. Also, due to how common other operations on interest rates are, it may make more sense on a program scale to do the rate/100 early in the program and internally store these rates as the actual rate in per unit, instead of the artificail percent (that would also allow parts of the code to use permill if that was desired (per mill is per 1000 instead of percent which is per 100).
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-12-27 00:47 +0000 |
| Message-ID | <sqb2f3$qtd$2@dont-email.me> |
| In reply to | #164090 |
On Sun, 26 Dec 2021 21:30:00 +0000, Manu Raju wrote: > On 26/12/2021 19:22, Lew Pitcher wrote: >> >> >> Your use of 1200 is confusing, unless you already know that it facilitates the >> conversion of a yearly interest rate expressed as a percent into a monthly >> interest rate expressed as a decimal. It is worth noting that, should you >> change the loan period expressed in P, you would /also/ have to change this >> 1200 "magic number" appropriately (or is P a "loan period in years"? if so, >> then I believe that your interest calculations are wrong.) >> >> > > The figure of 1200 will NEVER change. There will always be 12 months in > a year and we will always have to divide by 100 to express percentage as > decimals. 30 years ago, when I bought my house, I took out a mortgage. The bank offered me options to pay in monthly installments, or bi-weekly installments. The bi-weekly installment option offered a lower individual payment, but at a higher frequency. So, /yes/, the number of installments per cycle /may/ change. As for 1200 being an appropriate figure, I disagree. Your 1200 represents /two/ distinct conversion factors. Speaking from a purely "design" point of view, you never want constants to represent more than one thing. In this case, your 1200 represents a) the conversion factor that alters values expressed as a percent into values expressed as a decimal, and b) the conversion factor that alters values expressed as a year into values expressed as a number of months. While it may be convenient for /you/ to consolidate those two conversion factors into one constant, that consolidation /is not/ obvious, and /can/ lead to issues if one or the other of those two conversions change. Remember, you are writing code to be /readable/. The computer doesn't care; it doesn't know C from COBOL or Brainfuck: it only knows the ones and zeros that represent it's internal language. What you write must be readable and comprehensible to other programmers. [snip] -- Lew Pitcher "In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Guillaume <message@bottle.org> |
|---|---|
| Date | 2021-12-29 17:52 +0100 |
| Message-ID | <sqi3p9$1bia$1@gioia.aioe.org> |
| In reply to | #164059 |
Le 25/12/2021 à 06:44, Andrey Tarasevich a écrit :
> On 12/24/2021 5:00 PM, Manu Raju wrote:
>>>
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>> #include <math.h>
>>>
>>> int main()
>>> {
>>> float P = 100000; // Loan Amount
>>> float r = 7.5; // Advertised Interest Rate
>>> int n = 12; // Loan Period
>>> float payBack = (P * r / 1200 * pow(1 + r / 1200, n)) / (pow((1 +
>>> r / 1200), n) - 1);
>>> float Opening = P; // Opening Balance
>>> float closing = 0; // Closing Balance
>>> float interest = 0;
>>> float Total = 0;
>>> float repaid = 0;
>>>
>>> printf("\nMonthly payment is: %.2f\n", payBack);
>>>
>>> printf("%10s %14s %13s %10s %14s %12s\n", "Month", "Beginning",
>>> "Interest", "Total", "Repayment", "Balance");
>>>
>>> for (int i = 1; i <= n; i++)
>>> {
>>> for (int j = 0; j <= n; j++)
>>> {
>>> interest = Opening * r / 1200;
>>> Total = Opening + interest;
>>> repaid = payBack;
>>> closing = Total - payBack;
>>> }
>>> printf("%10d %14.0f %13.0f %10.0f %14.0f %12.0f\n", i,
>>> Opening, interest, Total, repaid, closing);
>>> Opening = closing;
>>> }
>>> return 0;
>>> }
>
> Certainly.
>
> 1. int main(void)
>
> 2. Stop using `float` for local variables. "Default" floating-point type
> in C is `double`. Everything else is used only if you have a good reason
> to do that. In this case you don't.
>
> 3. Stop using "regular" floating point types for representing monetary
> quantities. They are not good for that purpose.
>
> 4. It appears that you are actually trying to use `float` to represent
> _integer_ quantities (judging by your `printf`). Why?
>
> 5. Stop using `pow` for calculating integer powers. You don't really
> need `<math.h>` here.
>
> 6. Stop piling up all variable declarations at the beginning of the
> function. Declare variables as locally as possible.
>
> 7. Stop using dummy initializers for your variables. It is better to
> leave them uninitialized than initialize them to dummy zeros. This point
> is actually connected to the previous one: once you start declaring
> variables as locally as possible, you'll normally have a meaningful
> initializers for them at the point of declaration.
>
> 8. What's going on with capitalization in your variables names?
> `Opening`, `closing`, `interest`, `Total`? Is this a convention of some
> sort?
>
> 9. "Magical constants"? What on Earth is `1200`?
>
> 10. Repetitive subexpressions, like `1 + r / 1200` (some explicit, some
> slightly obfuscated) are probably a matter of style.... But anyway: DRY
> - do not repeat yourself.
All good points!
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-12-29 17:49 +0000 |
| Message-ID | <sqi72e$q7e$1@dont-email.me> |
| In reply to | #164099 |
On 29/12/2021 16:52, Guillaume wrote: > Le 25/12/2021 à 06:44, Andrey Tarasevich a écrit : >> 1. int main(void) >> >> 2. Stop using `float` for local variables. "Default" floating-point >> type in C is `double`. Everything else is used only if you have a good >> reason to do that. In this case you don't. >> >> 3. Stop using "regular" floating point types for representing monetary >> quantities. They are not good for that purpose. >> >> 4. It appears that you are actually trying to use `float` to represent >> _integer_ quantities (judging by your `printf`). Why? >> >> 5. Stop using `pow` for calculating integer powers. You don't really >> need `<math.h>` here. >> >> 6. Stop piling up all variable declarations at the beginning of the >> function. Declare variables as locally as possible. >> >> 7. Stop using dummy initializers for your variables. It is better to >> leave them uninitialized than initialize them to dummy zeros. This >> point is actually connected to the previous one: once you start >> declaring variables as locally as possible, you'll normally have a >> meaningful initializers for them at the point of declaration. >> >> 8. What's going on with capitalization in your variables names? >> `Opening`, `closing`, `interest`, `Total`? Is this a convention of >> some sort? >> >> 9. "Magical constants"? What on Earth is `1200`? >> >> 10. Repetitive subexpressions, like `1 + r / 1200` (some explicit, >> some slightly obfuscated) are probably a matter of style.... But >> anyway: DRY - do not repeat yourself. > > All good points! > All? 2) Nothing wrong with using 'float' when it's appropropriate. Many libraries eg. OpenGL make extensive use of float. It's not obvious that C's /default/ float type is 'double', nor that 'float' is not the default float type, despite the name! However, for this application, float is not quite accurate enough. 3) Double is perfectly suitable for representing monetary amounts, especially in a toy program or for personal use. (I've used it for accounts within a small business.) But what exactly would be a practical alternative here? To import a decimal float library, or somehow work with int64 whole cents? (Good luck with interest calculations with that.) 4) Doesn't make sense. The quantities have to be floating point, but are simply being printed with zero decimal places, as whole dollars or whatever. 5) I can't see an issue in using pow() to do pow(float,int); the result will not be exact anyway. What is the alternate, to invent a local powint(float,int) routine? Which will probably contain a loop. Or change the logic for an accumulative product. pow() is simpler! 6) I just don't agree with this at all. I like all the cluttery declarations out of the way of the logic, and in one place for quick reference. Then you also know there are no multiple, incompatible instances of any local identifier. 7) I think initialisers are a good idea. Some languages will ensure such locals are set to a known starting value, like 0 or 0.0 for static types; presumably they think that is a benefit. Ones like (1) I agree with, but I also think it's a waste of time pointing it out, as the practice is so widespread. Because compilers [not mine!] have long routinely accepted () parameter lists without any warnings that args passed to those functions are completely unchecked for number or types, most seem to assume that they mean /no/ parameters. In this example program, it means that the code could call main(10, 20.0, "three") without comment. But then it could still call it legally as main() if the (void) was added.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2021-12-29 11:33 -0800 |
| Message-ID | <sqid71$bnf$1@dont-email.me> |
| In reply to | #164100 |
On 12/29/2021 9:49 AM, Bart wrote: > On 29/12/2021 16:52, Guillaume wrote: >> Le 25/12/2021 à 06:44, Andrey Tarasevich a écrit : > > >>> 1. int main(void) >>> >>> 2. Stop using `float` for local variables. "Default" floating-point >>> type in C is `double`. Everything else is used only if you have a >>> good reason to do that. In this case you don't. >>> >>> 3. Stop using "regular" floating point types for representing >>> monetary quantities. They are not good for that purpose. >>> >>> 4. It appears that you are actually trying to use `float` to >>> represent _integer_ quantities (judging by your `printf`). Why? >>> >>> 5. Stop using `pow` for calculating integer powers. You don't really >>> need `<math.h>` here. >>> >>> 6. Stop piling up all variable declarations at the beginning of the >>> function. Declare variables as locally as possible. >>> >>> 7. Stop using dummy initializers for your variables. It is better to >>> leave them uninitialized than initialize them to dummy zeros. This >>> point is actually connected to the previous one: once you start >>> declaring variables as locally as possible, you'll normally have a >>> meaningful initializers for them at the point of declaration. >>> >>> 8. What's going on with capitalization in your variables names? >>> `Opening`, `closing`, `interest`, `Total`? Is this a convention of >>> some sort? >>> >>> 9. "Magical constants"? What on Earth is `1200`? >>> >>> 10. Repetitive subexpressions, like `1 + r / 1200` (some explicit, >>> some slightly obfuscated) are probably a matter of style.... But >>> anyway: DRY - do not repeat yourself. >> >> All good points! >> > > 2) Nothing wrong with using 'float' when it's appropropriate. Many > libraries eg. OpenGL make extensive use of float. That's just emphasizes my the point. The main purpose of "small" types, like `float`, `short`, char as plain integer, bit-fields etc. is to save memory in quantitatively massive data structures. That's exactly what OpenGL is intended to work with: massive amounts of geometric data. That's why it opts for `float` Everything else is just a consequence of that. > It's not obvious that C's /default/ float type is 'double', nor that > 'float' is not the default float type, despite the name! It doesn't have to be obvious. That's why I state it explicitly. > 6) I just don't agree with this at all. I like all the cluttery > declarations out of the way of the logic, Declarations are never cluttery, unless you make a deliberate effort to make them that. > and in one place for quick reference. Piling up all variable declarations in one place makes for much slower reference: first, one has has to find the pile, then one has to sift through the pile. Local declarations are always instantly visible, making for much quicker reference. Basically, with local declarations the matter of "reference" is virtually non-existent: the required knowledge is almost always naturally and intuitively present within the field of view. The popular counter-argument stating that "functions have to be small with small number of variables" is nothing else that a fake advice whose only purpose is to serve as an emergency brace for the cracking and crumbling bad practice of piling up variable declarations. > Then you also know there are no multiple, incompatible > instances of any local identifier. This is a classic "solution looking for a problem": a solution for a problem that does not really exist in the first place. > 7) I think initialisers are a good idea. Some languages will ensure such > locals are set to a known starting value, like 0 or 0.0 for static > types; presumably they think that is a benefit. It definitely has a benefit: it works as a bootstrapping point for static/dynamic initialization. I.e. gives you a reliable anchoring point: something that is guaranteed to be there "even before the programs starts", without you having to worry about the initialization and associated ordering issues. No other reason. And this, of course, does not apply outside of static initialization contexts. The only thing you achieve by using dummy initializers is defeat checks performed by static/dynamic analysis tools. -- Best regards, Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-12-29 22:45 -0500 |
| Message-ID | <sqja15$ea4$1@dont-email.me> |
| In reply to | #164101 |
On 12/29/21 2:33 PM, Andrey Tarasevich wrote: > On 12/29/2021 9:49 AM, Bart wrote: ... >> It's not obvious that C's /default/ float type is 'double', nor that >> 'float' is not the default float type, despite the name! > > It doesn't have to be obvious. That's why I state it explicitly. Stating it explicitly is not as good as providing relevant citations. That was certainly true in K&R C, where the usual arithmetic conversions always caused float operands to be converted to double, and the default argument promotions caused float arguments to be promoted to double. However, in C90 the usual arithmetic conversions were changed so that floating-point operands were never converted to a higher precision unless the other operand had a higher precision. In C90, none of the standard library functions took a float or long double argument, but that changed in C99 - all of the math.h functions now come in three different forms: one suffixed with 'f' that takes float arguments and/or returns float values, one with no suffix for double, and on suffixed with 'l' for long double. C90 also introduced function prototypes. When calling a function with a prototype declaration in scope (which is now the normal case), the default argument promotions occur only for the variable parts of variadic functions. That's the only sense in which "double is the default" survived past C99. I'd say that, since C99, it's far from obvious that double is the default precision, and I'd say that the reason it's not obvious is because it's no longer true.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2021-12-30 00:35 -0800 |
| Message-ID | <sqjr1g$jd5$1@dont-email.me> |
| In reply to | #164113 |
On 12/29/2021 7:45 PM, James Kuyper wrote: > > I'd say that, since C99, it's far from obvious that double is the > default precision, and I'd say that the reason it's not obvious is > because it's no longer true. A rather obvious fact that an unsuffixed `0.0` is a `double` still grants a significant degree of defaultness (sic) to `double`. -- Best regards, Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-12-30 10:19 +0100 |
| Message-ID | <sqjtip$1km$1@dont-email.me> |
| In reply to | #164115 |
On 30/12/2021 09:35, Andrey Tarasevich wrote: > On 12/29/2021 7:45 PM, James Kuyper wrote: >> >> I'd say that, since C99, it's far from obvious that double is the >> default precision, and I'd say that the reason it's not obvious is >> because it's no longer true. > > A rather obvious fact that an unsuffixed `0.0` is a `double` still > grants a significant degree of defaultness (sic) to `double`. > If you call a function for which there is no prototype (I think it is insane that non-prototype declarations are still allowed in C, even C18, but that's a side point) then any arguments of type "float" are promoted to "double". The same applies to arguments to a function with a variable number of arguments (in the ellipsis part). That adds to the "double is default" argument (though I agree with James that it is much less the default in C99 than it was in C90).
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2022-01-01 18:19 +0000 |
| Message-ID | <sqq5um$udk$1@dont-email.me> |
| In reply to | #164101 |
On 29/12/2021 19:33, Andrey Tarasevich wrote:
> On 12/29/2021 9:49 AM, Bart wrote:
>> 2) Nothing wrong with using 'float' when it's appropropriate. Many
>> libraries eg. OpenGL make extensive use of float.
>
> That's just emphasizes my the point. The main purpose of "small" types,
> like `float`, `short`, char as plain integer, bit-fields etc. is to save
> memory in quantitatively massive data structures.
>
> That's exactly what OpenGL is intended to work with: massive amounts of
> geometric data. That's why it opts for `float` Everything else is just a
> consequence of that.
It has to give acceptable results. Presumably float's accuracy is
sufficient for that. Using less memory, and being somewhat faster, are
bonuses.
>> and in one place for quick reference.
>
> Piling up all variable declarations in one place makes for much slower
> reference: first, one has has to find the pile, then one has to sift
> through the pile.
>
> Local declarations are always instantly visible,
That's the problem! If trying to appreciate the algorithm, the types and
attributes of the variables are secondary.
Also, the type is only applied to the first occurence. You see
'interest' being used on a subsequent; what type is it? You glance at
the top of the function - it's not there! You have to scan backwards
from where you are until you encounter a matching declaration.
But then, if 'interest' /was/ declared at the top, now you are wasting
type doing that scan.
(This is a simple program. Have a look at something like the amalgmated
source file of sqlite3.c, where they really take your style on board.
You also have to contend with names with appear identical but have
subtle differences, or the same name declared more than once in the same
function. If you miss the first declaration on that backwards scan, you
may end up at the wrong one.
Look at the two declarations of pKeyInfo in this extract:
if( pPart || pOrderBy ){
int nPart = (pPart ? pPart->nExpr : 0);
int addrGoto = 0;
int addrJump = 0;
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
if( pPart ){
int regNewPart = reg + pMWin->nBufferCol;
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart,
pMWin->regPart,nPart);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
VdbeCoverageEqNe(v);
windowAggFinal(pParse, pMWin, 1);
if( pOrderBy ){
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
}
}
if( pOrderBy ){
int regNewPeer = reg + pMWin->nBufferCol + nPart;
int regPeer = pMWin->regPart + nPart;
if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
if( pMWin->eType==TK_RANGE ){
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse,
pOrderBy, 0, 0);
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer,
nPeer);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
VdbeCoverage(v);
}else{
addrJump = 0;
}
windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT);
if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
}
Note that I've helped you by isolating the lines with both declarations,
but some functions are considerably longer, such as one of 750 lines
with 3 versions of "pPk".
Yet another delight is a 7000-line function, which uses names such as
"pcx" and "pCx" (with different types), or "pVtab" (of type sqlite_vtab)
and "pVTab" (of type VTABLE!).
All the 300+ locals in this function are listed below. Not all identical
names have the same type (eg. 'len' exists as 'long' and also 'int').
If all were listed at the top, there would necessarily be fewer as you
couldn't have duplicates (some will be labels), but if sorted like this
must surely be easier to find than scanning 7000 lines of dense code.
----------------------------------------------
(Sorry the types are not in proper C syntax. Names with void types are
labels.)
abort_due_to_error void
abort_due_to_interrupt void
aEQb [6]const uchar
affinity schar
aFlag [2]const ushort
aGTb [6]const uchar
alreadyExists int
aLTb [6]const uchar
aMem ref struct sqlite3_value
and_logic [9]const uchar
aOffset ref uint
aOp ref struct VdbeOp
apArg ref ref struct sqlite3_value
apArg ref ref struct sqlite3_value
aPermute ref int
aRes [3]int
arithmetic_result_is_null void
aRoot ref int
aZero [16]uchar
azType [4]const ref const schar
bIntint schar
bRev int
c int
c int
check_for_interrupt void
cnt int
cnt int
compare_op void
Compiling sqlite3.c to sqlite3.exe
db ref struct sqlite3
desiredAutoCommit int
encoding uchar
eNew int
eOld int
eqOnly int
exists int
file_format int
flags ushort
flags1 ushort
flags3 ushort
fp_math void
i int
i int
i int
i int
i int
i int
i int
i int
i int
i int
iA llong
iA llong
iAddr uint
iB llong
iB llong
iCompare int
iCookie int
iDb int
iDb int
iDb int
iDb int
idx int
ii int
ii int
iKey llong
iKey ullong
iMeta int
iMeta int
iMoved int
initData struct (ref struct sqlite3 db,ref ref
schar pzErrMsg,int iDb,int rc,uint mInitFlags)
iPrior uint
iQuery int
iRollback int
iSavepoint int
iSet int
isLegacy int
isNotInt int
isSchemaChange int
isTransaction int
isWriteLock uchar
j int
jump_to_p2 void
jump_to_p2_and_check_for_interrupt void
len int
len uint
n int
n int
n int
n int
n int
n uint
nArg int
nArg int
nByte int
nByte llong
nByte llong
nChange int
nData ullong
nEntry llong
nErr int
newMax uint
next_tail void
nField int
nField int
nField int
nHdr int
nKeyCol int
nMem int
nName int
no_mem void
nProgressLimit uint
nRoot int
nullFlag ushort
nVarint int
nVmStep uint
nZero llong
oc int
offset64 ullong
On line: 140
op uchar
op_column_corrupt void
op_column_out void
op_column_read_header void
open_cursor_set_hints void
opflags int
or_logic [9]const uchar
origFlags ushort
p ref struct Vdbe
p1 int
p1 int
p1 int
p1 int
p2 int
p2 int
p2 int
p2 int
pArgc ref struct sqlite3_value
pBt ref struct Btree
pBt ref struct Btree
pBt ref struct Btree
pBt ref struct Btree
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pC ref struct VdbeCursor
pCaller ref struct VdbeOp
pcDest int
pColl ref struct CollSeq
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCrsr ref struct BtCursor
pCtx ref struct sqlite3_context
pCtx ref struct sqlite3_context
pCtx ref struct sqlite3_context
pCtx ref struct sqlite3_context
pCur ref struct VdbeCursor
pCur ref struct VdbeCursor
pCur ref struct VdbeCursor
pCur ref struct VdbeCursor
pCur ref struct VdbeCursor
pcx int
pCx ref struct VdbeCursor
pCx ref struct VdbeCursor
pCx ref struct VdbeCursor
pCx ref struct VdbeCursor
pData ref struct sqlite3_value
pData0 ref struct sqlite3_value
pDb ref struct Db
pDb ref struct Db
pDb ref struct Db
pDest ref struct sqlite3_value
pDest ref struct sqlite3_value
pEnd ref struct sqlite3_value
pFrame ref struct VdbeFrame
pFrame ref struct VdbeFrame
pFrame ref struct VdbeFrame
pFrame ref struct VdbeFrame
pFrame ref struct VdbeFrame
pFree ref struct UnpackedRecord
pgno int
pgno int
pIdxKey ref struct UnpackedRecord
pIn ref struct sqlite3_value
pIn1 ref struct sqlite3_value
pIn2 ref struct sqlite3_value
pIn3 ref struct sqlite3_value
pKey ref struct sqlite3_value
pKeyInfo ref struct KeyInfo
pKeyInfo ref struct KeyInfo
pKeyInfo ref struct KeyInfo
pLast ref struct sqlite3_value
pMem ref struct sqlite3_value
pMem ref struct sqlite3_value
pMem ref struct sqlite3_value
pMem ref struct sqlite3_value
pMem ref struct sqlite3_value
pMem ref struct sqlite3_value
pModule ref struct sqlite3_module
pModule ref struct sqlite3_module
pModule ref struct sqlite3_module
pModule ref struct sqlite3_module
pModule ref struct sqlite3_module
pModule ref struct sqlite3_module
pName ref struct sqlite3_value
pnErr ref struct sqlite3_value
pNew ref struct Savepoint
pOp ref struct VdbeOp
pOrig ref struct VdbeCursor
pOut ref struct sqlite3_value
pPager ref struct Pager
pProgram ref struct SubProgram
pQuery ref struct sqlite3_value
pRec ref struct sqlite3_value
pReg ref struct sqlite3_value
pRt ref struct sqlite3_value
pSavepoint ref struct Savepoint
pTab ref struct Table
pTab ref struct Table
pTabCur ref struct VdbeCursor
pTmp ref struct Savepoint
pVar ref struct sqlite3_value
pVCur ref struct sqlite3_vtab_cursor
pVCur ref struct sqlite3_vtab_cursor
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVtab ref struct sqlite3_vtab
pVTab ref struct VTable
pX ref struct Btree
pX ref struct sqlite3_value
r struct (ref struct KeyInfo pKeyInfo,ref
struct sqlite3_value aMem,ushort nField,schar default_rc,uchar
errCode,schar r1,schar r2,uchar eqSeen)
r struct (ref struct KeyInfo pKeyInfo,ref
struct sqlite3_value aMem,ushort nField,schar default_rc,uchar
errCode,schar r1,schar r2,uchar eqSeen)
r struct (ref struct KeyInfo pKeyInfo,ref
struct sqlite3_value aMem,ushort nField,schar default_rc,uchar
errCode,schar r1,schar r2,uchar eqSeen)
r struct (ref struct KeyInfo pKeyInfo,ref
struct sqlite3_value aMem,ushort nField,schar default_rc,uchar
errCode,schar r1,schar r2,uchar eqSeen)
rA double
rB double
rc int
res int
res int
res int
res int
res int
res int
res int
res int
res int
res int
res int
res int
res int
res2 int
resetSchemaOnFault uchar
rowid llong
rowid llong
sContext struct (ref struct sqlite3_value pOut,ref
struct FuncDef pFunc,ref struct sqlite3_value pMem,ref struct Vdbe
pVdbe,int iOp,int isError,uchar skipFlag,uchar argc,[1]ref struct
sqlite3_value argv)
seek_not_found void
seekResult int
serial_type uint
sMem struct (union MemValue u,ushort
flags,uchar enc,uchar eSubtype,int n,ref schar z,ref schar zMalloc,int
szMalloc,uint uTemp,ref struct sqlite3 db,ref proc(ref void)void xDel)
sMem struct (union MemValue u,ushort
flags,uchar enc,uchar eSubtype,int n,ref schar z,ref schar zMalloc,int
szMalloc,uint uTemp,ref struct sqlite3 db,ref proc(ref void)void xDel)
sz llong
t ref void
t uint
takeJump int
too_big void
type1 ushort
type2 ushort
uA ullong
v llong
v llong
v1 int
v2 int
val llong
vdbe_return void
vfsFlags const int
vtabOnConflict uchar
wrFlag int
x llong
x ref proc(ref void,ref const schar)void
x struct (ref const void pKey,llong
nKey,ref const void pData,ref struct sqlite3_value aMem,ushort nMem,int
nData,int nZero)
x struct (ref const void pKey,llong
nKey,ref const void pData,ref struct sqlite3_value aMem,ushort nMem,int
nData,int nZero)
z ref const schar
z ref schar
z ref schar
z ref schar
zAffinity ref const schar
zAffinity ref schar
zData ref const uchar
zDb ref const schar
zDb ref const schar
zEndHdr ref const uchar
zFilename ref const schar
zHdr ref const uchar
zMaster ref const schar
zName ref schar
zNewRecord ref uchar
zSql ref schar
zTab ref const schar
zTrace ref schar
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2022-01-01 19:33 +0000 |
| Message-ID | <sqqab7$sbi$1@dont-email.me> |
| In reply to | #164201 |
On 01/01/2022 18:19, Bart wrote: > On 29/12/2021 19:33, Andrey Tarasevich wrote: >> Local declarations are always instantly visible, [Summary of local variables from a giant sqlite3.c function] > nByte int > nByte llong > nByte llong Don't get caught out! > nField int > nField int > nField int > p1 int > p1 int > p1 int > p1 int > pBt ref struct Btree > pBt ref struct Btree > pBt ref struct Btree > pBt ref struct Btree > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pC ref struct VdbeCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pCrsr ref struct BtCursor > pFrame ref struct VdbeFrame > pFrame ref struct VdbeFrame > pFrame ref struct VdbeFrame > pFrame ref struct VdbeFrame > pFrame ref struct VdbeFrame > res int > res int > res int > res int > res int > res int > res int > res int > res int > res int > res int > res int > res int > res2 int The above sets of identical names highlight other problems with local declarations. Take the 24 versions of 'pC', with struct VdbeFrame*; suppose the type needed to change; now you have to change 24 versions of it. But, you won't know there are 24 versions; you will need to hunt them down. Maybe some of the 24 are unrelated in use, and need to stay the same type. But the function has mixed them all up in the same way that all instances of a literal '1200' can be mixed up in a program. > x llong > x ref proc(ref void,ref const schar)void > x struct (ref const void pKey,llong I haven't analysed how these names relate to each within the block structure. But suppose the x's are in nested blocks, and one declaration is missed out. That one may be shadowing an outer 'x' - of the wrong type. With luck, its used will cause a type error, but if not... > nKey,ref const void pData,ref struct sqlite3_value aMem,ushort nMem,int > nData,int nZero) > x struct (ref const void pKey,llong > nKey,ref const void pData,ref struct sqlite3_value aMem,ushort nMem,int > nData,int nZero) > z ref const schar > z ref schar > z ref schar > z ref schar ... or it ends up with a version that has a missing 'const'. Even when they're all the same type, you could end writing or reading into the wrong variable.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-12-29 14:37 -0800 |
| Message-ID | <87sfub2g2t.fsf@nosuchdomain.example.com> |
| In reply to | #164100 |
Bart <bc@freeuk.com> writes:
[...]
> 3) Double is perfectly suitable for representing monetary amounts,
> especially in a toy program or for personal use. (I've used it for
> accounts within a small business.)
In a toy program, sure -- and I'd say *only* in a toy program.
Using floating-point for money risks, at best, rare off-by-one errors,
such as a computation yielding a result one cent off from the correct
value. I believe that would be considered unacceptable in any
real-world financial application.
> But what exactly would be a practical alternative here? To import a
> decimal float library, or somehow work with int64 whole cents? (Good
> luck with interest calculations with that.)
If you only need to do calculations that yield whole numbers of cents,
then yes, you can use a wide integer (long long or uint64_t, for
example, or define your own type "in64" if you insist for some reason)
with a scaling factor of 100. If you need to do interest calculations
in the real world (not in a toy program), you need to find out the exact
rules for those calculations and implement them.
[...]
> 5) I can't see an issue in using pow() to do pow(float,int); the
> result will not be exact anyway. What is the alternate, to invent a
> local powint(float,int) routine? Which will probably contain a
> loop. Or change the logic for an accumulative product. pow() is
> simpler!
Integer exponentiation can be done exactly (assuming no overflow).
pow() can suffer floating-point errors. Whether pow() is acceptable
depends on the application and the financial rules governing it.
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
Page 1 of 6 [1] 2 3 4 5 6 Next page →
Back to top | Article view | comp.lang.c
csiph-web