1. Novice Level Project - simple, fun and useful
- Posted by Senator Sep 23, 2020
- 1712 views
Greetings All,
After a few years in and out of the hospital, I decided I had better get a better handle on my finances. So I wrote a very simple little program I call "Budget Buddy" using the Euphoria Database System (EDS).
I created has two main tables - register, and cash. I record my income as deposits, expenditures and cash withdrawals as debits in/from the register table. The register table has only three fields: a datetime date is the key for each for each entry, The second field is a transaction note, and the last field is the transaction amount. Debits are entered and maintained internally as negative numbers, but in table listings they are reported without a sign and color coded red. Deposits are color coded blue.
Cash debits from the register table are "deposited" into the cash table which has the same structure and operation as the register table.
Transaction notes which exceed the allotted space are truncated with an asterisk color coded yellow.
In the table listings the current balance is calculated on the fly.
register # Day Transaction Amount BALANCE ----------------------------------------------------------------------------------- 44 8-17 Debit cash $300.00 $4,141.40 ---- 74 9-21 Accordia PA Amanda referring me to ~ $60.00 $1,391.60 75 9-21 Walmart groceries $93.87 $1,297.73 -----------------------------------------------------------------------------------A menu selection calls a routine which displays the full record:
Display full note of record #: 74 74 9-21 Accordia PA Amanda referring me to Cardiologist. Suggested a Urologist in Dublin. Next appointment 12-21-20 walk in. $60.00
CASH # Day Transaction Amount BALANCE ----------------------------------------------------------------------------------- 1 7-6 Cash on hand $233.21 $233.21 2 7-6 groceries $40.00 $193.21 3 7-13 ALLCARE ADDERALL MEDICAL $14.40 $178.81
Reports of expenditures can be generated using search terms from the transaction notes:
<keyword: GROCERIES> Year: 2020 Month: 8 ----------------------------------------------------------------------------------- *****register***** 33 8-3 groceries Walmart $98.82 34 8-3 groceries meat Thriftway $266.19 total $365.01 ----------------------------------------------------------------------------------- *****CASH***** 19 8-17 groceries Walmart $40.00 20 8-17 groceries Thriftway $22.00 total $62.00 ----------------------------------------------------------------------------------- total $427.01I wrote several menu selected routines to edit the record data:
#:79 DATE: 2020-9-26-4-10-13 1 Transaction Note: autolog DEPOSIT interest paid 2 $ 2.48 Enter # of data element to edit, Enter 0 to abort: 1 Transaction Note: autolog DEPOSIT interest paid 1. Append Keyword to transaction note 2. Replace Keyword in transaction note 3. Remove Keyword in transaction note 4. Replace entire transaction note
I also added a budget table which contains my income and budget category data. Each time the program is executed a file called AUTOLOG.DAT which contains the month number of the last budget autolog. If the AUTOLOG.DAT month is not the current month, the database is backed up and then the budget table data is automatically logged into the register table. The AUTOLOG.DAT file is then updated. I added a prompt with an opt-out option for good measure. The budget data can also be autologged from a menu selection.
Regards, Ken
2. Re: Novice Level Project - simple, fun and useful
- Posted by irv Sep 23, 2020
- 1694 views
Sorry to hear about the hospitalizations. Hope you're better now!
That seems like a useful program, care to share?
3. Re: Novice Level Project - simple, fun and useful
- Posted by ChrisB (moderator) Sep 24, 2020
- 1676 views
Hi
Are you recording values as whole numbers, or as decimals? It won't matter so much when you are only doing addition and subtraction, but if it ever does tax or percentage calculations, then it can lead to rounding errors - I made this mistake in my veterinary practice management program, and had to a lot of little 'kludges' later ro get the right tax calculations.
Nice project.
Cheers
Chris
4. Re: Novice Level Project - simple, fun and useful
- Posted by Senator Sep 24, 2020
- 1642 views
Sorry to hear about the hospitalizations. Hope you're better now!
That seems like a useful program, care to share?
Thanks, Irv - I'm doing fairly well health wise.
I will try to clean-up my code a bit and post something today or tomorrow.
Regards, Ken
5. Re: Novice Level Project - simple, fun and useful
- Posted by ghaberek (admin) Sep 24, 2020
- 1636 views
Are you recording values as whole numbers, or as decimals? It won't matter so much when you are only doing addition and subtraction, but if it ever does tax or percentage calculations, then it can lead to rounding errors - I made this mistake in my veterinary practice management program, and had to a lot of little 'kludges' later ro get the right tax calculations.
Is tracking money values as integers of pennies usually the best approach then?
-Greg
6. Re: Novice Level Project - simple, fun and useful
- Posted by Senator Sep 24, 2020
- 1630 views
Hi
Are you recording values as whole numbers, or as decimals? It won't matter so much when you are only doing addition and subtraction, but if it ever does tax or percentage calculations, then it can lead to rounding errors - I made this mistake in my veterinary practice management program, and had to a lot of little 'kludges' later ro get the right tax calculations.
Nice project.
Cheers
Chris
Thanks.
Values are entered/recorded/stored as atoms. Negative values,debits, are initially entered as positive numbers then multiplied by -1 to produce a negative number which is then stored. When viewing a negative value which is to be edited, it is displayed with its sign and the new negative value is entered including the sign.
I enter values with two decimal places c.f. 25.00. I have noticed when editing such a value is displayed as 25 with no decimal point; however, 25.25 displays for editing as 25.25.
Any suggestions for improvement will be appreciated.
Thanks, Ken
7. Re: Novice Level Project - simple, fun and useful
- Posted by katsmeow Sep 24, 2020
- 1623 views
Any suggestions for improvement will be appreciated.
Thanks, Ken
String math. I believe there's libs in the archives, for multiple numeric bases too. Solves the whole human-decimal to computer-binary issue.
Kat
8. Re: Novice Level Project - simple, fun and useful
- Posted by Spock Sep 24, 2020
- 1654 views
Are you recording values as whole numbers, or as decimals? It won't matter so much when you are only doing addition and subtraction, but if it ever does tax or percentage calculations, then it can lead to rounding errors - I made this mistake in my veterinary practice management program, and had to a lot of little 'kludges' later ro get the right tax calculations.
Is tracking money values as integers of pennies usually the best approach then?
-Greg
This is what I do for currency values in my office programs. Conversion is only done for displaying the value or saving to file. OTOH for currency rates I use doubles.
Spock
9. Re: Novice Level Project - simple, fun and useful
- Posted by ChrisB (moderator) Sep 25, 2020
- 1589 views
Hi
Yes, exactly. You'll be ok mostly for addition and subtraction, but once you start doing splits and percentages, then you'll start to see 'not quite right' errors creeping in.
Cheers
Chris
10. Re: Novice Level Project - simple, fun and useful
- Posted by Senator Sep 26, 2020
- 1530 views
Thanks for all the feedback.
I was just about to post my code... but first let me see if I have this right...
I obtain the value as an atom/decimal number say, 100.36 then
multiply it by 100, converting it to 10036 an integer, and store
that value in the data base.
When I display that value I simply divide it by 100
and everything is copasetic, right?
I already have 81 records in the database now.
It shouldn't be hard to loop through those records converting the stored value to integers/pennies.
Regards, Ken
11. Re: Novice Level Project - simple, fun and useful
- Posted by irv Sep 26, 2020
- 1535 views
You may find it helpful to display the numbers using something like:
display("$ [:8,,.2]",n/100)
This will allow columns to line up neatly, and add commas, e.g: $ 1,234.56
12. Re: Novice Level Project - simple, fun and useful
- Posted by petelomax Sep 26, 2020
- 1546 views
display("$ [:8,,.2]",n/100)
Ugh, display(), ugh. Sorry, but there is no limit to the amount of scorn and vitriol I could pour on that sad excuse of a routine and it's illegitimate sibling, text_format(), pttth.
No doubt it has it's fans here, but if you don't believe me, just look for yourself at the docs or better yet the ridiculous and revolting source code, especially the latter, like some kind of weird regex on acid.
It is not and I have no plans to ever make it compatible with Phix, however the following dose of sanity will give exactly the same results (in Phix, but sadly not Eu):
printf(1,"$ %,8.2f\n",n/100)
In fairness, for comparison, the latter is not exactly pretty either, but at least there is only one of it and it is far less than 1/4 the size, plus the above actually entirely depends upon a non-amendable (C) version of that anyway.
(The only thing Eu does not have is the comma handling, which is only like six lines of code anyway.)
PS OK, technically, display() runs fine (if that's a valid word here) on Phix, but I certainly ain't supporting or fixing or documenting it!
13. Re: Novice Level Project - simple, fun and useful
- Posted by ghaberek (admin) Sep 26, 2020
- 1522 views
Ugh, display(), ugh. Sorry, but there is no limit to the amount of scorn and vitriol I could pour on that sad excuse of a routine and it's illegitimate sibling, text_format(), pttth.
Agreed. I took one look at the documentation for display() and then immediately ignored it. No. Thank. You.
I don't really like Python's format() either. I guess .NET's String.Format() is alright.
Unfortunately this is a hard problem to solve, and I think we dropped the ball on that one.
-Greg
14. Re: Novice Level Project - simple, fun and useful
- Posted by irv Sep 26, 2020
- 1514 views
If it works, I use it.
Display is part of a library file (std/console.e) so you can post your neater, cleaner version any time!
15. Re: Novice Level Project - simple, fun and useful
- Posted by petelomax Sep 27, 2020
- 1479 views
Display is part of a library file (std/console.e) so you can post your neater, cleaner version any time!
I thought I just did, it's called printf()!
I can post the phix comma-insertion code if you like, and/or a phix-compatible version of sprintf() in javascript that I recently wrote.
16. Re: Novice Level Project - simple, fun and useful
- Posted by petelomax Sep 29, 2020
- 1406 views
- Last edited Oct 01, 2020
Coincidentally (while on a completely unrelated code-fragment-formatting-issue-mini-trawl) I just ran into the bankers rounding section of the phix docs, and was obviously reminded of this thread, and ended up completely rewriting both the previously frankly rubbish code and the previously rather dour and depressing documentation:
integer pennies = bankers_rounding(atom pence, integer precison=1)
In the standard round() function, exact .5s are rounded up (matching Euphoria) whereas banker's rounding yields the nearest even number, eg:
constant x1 = {-4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5} ?apply(x1,round) ?apply(x1,bankers_rounding) function precision100(atom xi) return bankers_rounding(xi*100,100) end function ?apply(x1,precision100) -- output: -- {-4,-3,-2,-1,0,1,2,3,4,5} -- {-4,-4,-2,-2,0,0,2,2,4,4} -- {-400,-400,-200,-200,0,0,200,200,400,400}
The reason you might want to use banker's rounding is so that the average of the rounded numbers is as close as possible to the average of the original numbers (ditto total), whereas always rounding up obviously introduces a systemic bias.
Above, the standard rounding average is out by 0.1, whereas the average x1 and the average bankers are both exactly zero (not that it would be difficult to construct a deliberately biased x1 such that the opposite were true; you only get better outputs for evenly-dispersed/unbiased inputs).
Note that this is only possible when working in whole (integer) pennies/cents (and above), not pounds/dollars to 2dp, and the precision is not inverted (see Technicalia). Should you want to store things in 2dp format, that's fine as long as you round(*100) to get exact whole integer penny/cent values back out when you retrieve them, that is prior to attempting any subsequent calculations that are likely to end up requiring any further banker's rounding, but of course you don't need to do that if all you're going to do is print or add and subtract them. [It should make no difference whatsoever if you use round() or bankers_rounding() to retrieve the whole integer penny/cent values.]
Technicalia:
Since eg 0.045 cannot be held exactly in an IEEE 754 floating point, it would be rather difficult to coerce it to (almost) 0.04 rather than (almost) 0.05 - it would instead naturally fall depending on whether the nearest admissible representation was out by +/-epsilon. An abs(frac-0.5)<1e-13 or similar rather than frac=0.5 (see pmaths.e below) might work, but could introduce another (small) bias of the very same kind that we are trying to eliminate. Best to just stick with integers. There is of course nothing to stop you taking a copy of bankers_rounding() and creating a (renamed) application specific version of it, tweaked however you like.
Likewise if bankers_rounding() had an inverted precision, inaccuracies in the representation of(eg) 0.01 could totally spanner it, hence it has an non-inverted (and integer) precision.
The integer return type of bankers_rounding is quite, quite, deliberate.
And the (new) code is just:
global function bankers_rounding(atom pence, integer precision=1) integer pennies, -- (or nearest 100, etc, but never nearest < 1 ) s = sign(pence), whole pence = abs(pence)/precision whole = floor(pence) atom fract = pence-whole if fract=0.5 then pennies = whole+and_bits(whole,1) else pennies = floor(0.5+pence) end if pennies *= s*precision return pennies end function
17. Re: Novice Level Project - simple, fun and useful
- Posted by Senator Oct 01, 2020
- 1359 views
Thanks for all the suggestions. I have tried to convert to integer storage and display of floating point data using Pete's bankers_rounding function.
Unfortunately I discovered a problem with corrupted line warnings escalating to a crash in display of my main table, register, data. I do not think the problem is related to my converting all my monetary data storage to integers. I just didn't notice the debug.log until I started gathering the program files to post here.
And things were going so well. Here is some excerpts from debug.logs and db_dumps. Any suggestions will be appreciated.
Running program from WEE editor: listing of the main table register appears normal up to the final record: 97 10-31 autolog SC Balance Requirement Fee (bal not shown) At which point the program crashed: Writing profile results to ex.pro ... ex.pro is an empty file Fatal run-time error: A machine-level exception occurred during execution of this statement (signal -17 /tmp/wee_run_196511.sh: line 3: 24388 Segmentation fault (core dumped) /home/ken/euphoria-4.1.0-Linux-x64/bin/eui -batch /home/ken/euprogs/Budget_Builder/register.ex Press any key... debug.log list numerous line corruption errors smaller table, cash, does not crash - displays as normal but a debug.log is generated with numerous line corrupted errors Running interpreter from terminal - just displaying the menu, generates a debug.log... /home/ken/euprogs/Budget_Builder/debug.log:1 <0117>:: Not expecting to see ''('' here line corrupted (26), s is 23, col is 0 The table listing and menu displays as normal, but selecting the cash table again generates more debug.log data **starting with record # 23** which is the same rec # where similar debug.log warnings started being reported for the register table. captured from screen 23 9-5 Tabatha Kitchens household $55.00 $66.00 24 9-8 McDonalds breakfast fast-food $8.00 $58.00 25 9-30 Lowes Wasp Hornet Spray $13.00 $45.00 cash table listing debug.log: line corrupted (26), s is 23, col is 0 line corrupted (26), s is 9-5, col is 6 line corrupted (26), s is Tabatha Kitchens household, col i line corrupted (26), s is $55.00, col is 49 line corrupted (26), s is $66.00, col is 66 line corrupted (26), s is , col is 72 line corrupted (27), s is 24, col is 0 line corrupted (27), s is 9-8, col is 6 line corrupted (27), s is McDonalds breakfast fast-food, co line corrupted (27), s is $8.00, col is 49 line corrupted (27), s is $58.00, col is 66 line corrupted (27), s is , col is 72 line corrupted (28), s is 25, col is 0 line corrupted (28), s is 9-30, col is 6 line corrupted (28), s is Lowes Wasp Hornet Spray, col is 1 line corrupted (28), s is $13.00, col is 49 line corrupted (28), s is $45.00, col is 66 ^ I cannot tell from db_dump that register.edb actual data has been corrupted. Example from cash table: key: {2020,9,5,10,48,42} data: { "Tabatha Kitchens household", -5485 } key: {2020,9,8,10,54,2} data: { "McDonalds breakfast fast-food", -800 } key: {2020,9,30,18,7,18} data: { "Lowes Wasp Hornet Spray", -1300 }
Any suggestions will be appreciated.
Regards, Ken
Forked into: Budget Builder
18. Re: Novice Level Project - simple, fun and useful
- Posted by Spock Oct 01, 2020
- 1351 views
Thanks for all the suggestions. I have tried to convert to integer storage and display of floating point data using Pete's bankers_rounding function.
Unfortunately I discovered a problem with corrupted line warnings escalating to a crash in display of my main table, register, data. I do not think the problem is related to my converting all my monetary data storage to integers. I just didn't notice the debug.log until I started gathering the program files to post here.
And things were going so well. Here is some excerpts from debug.logs and db_dumps. Any suggestions will be appreciated.
... ...
Regards, Ken
As much as possible I use CSV files for storing data. Each time the file is loaded the program verifies the syntax (occasionally some semantics too) of each field in each line. The file itself is human-readable so corrupt data can't really hide anywhere.
Spock
19. Re: Novice Level Project - simple, fun and useful
- Posted by petelomax Oct 03, 2020
- 1318 views
captured from screen 23 9-5 Tabatha Kitchens household $55.00 $66.00 cash table listing debug.log: line corrupted (26), s is Tabatha Kitchens household, col i line corrupted (26), s is $55.00, col is 49 line corrupted (26), s is $66.00, col is 66 I cannot tell from db_dump that register.edb actual data has been corrupted. Example from cash table: key: {2020,9,5,10,48,42} data: { "Tabatha Kitchens household", -5485 }
That tells me you're mixing up dbdump output from different register.edb.
It's either $55.00 or $54.85, not both.
I suspect your register.edb is corrupt and needs to be deleted/rebuilt.
You may be able to recover some records from it, try db_compress or doing it record-by-record by hand.
Sadly, .edb files are not very reliable. I used to have terrible trouble with edita.edb,
but now I only have to trash it every 3 or 4 years (which is down to not crashing and therefore
always calling db_close() which flushes any and all updates from memory, but when inevitably it does
crash, by which I mean for something completely unrelated to database handling, I'll probably start
experiencing corruption issues a week or month later, at a guess).
Pete