Willsy Posted March 21, 2017 Share Posted March 21, 2017 (edited) All ye faint of heart turn back and be gone, for here lies The Forth, and The Forth is The Way. Calculate the day of the week for any date since 1/1/1700. Note: BRITISH date format (day month year) is required. Ha! variable year variable month variable day create years 0 c, 3 c, 3 c, 6 c, 1 c, 4 c, 6 c, 2 c, 5 c, 0 c, 3 c, 5 c, create leap-years 6 c, 2 c, 3 c, 6 c, 1 c, 4 c, 6 c, 2 c, 5 c, 0 c, 3 c, 5 c, create centuries 4 c, 2 c, 0 c, 6 c, : century ( year - n ) 1700 /mod drop 100 / 4 mod centuries + c@ ; : leapYear? ( year - flag ) dup >r 400 mod 0= r@ 100 mod 0<> or r> 4 mod 0= and ; : dow ( day month year -- n ) dup century >r 100 mod year ! 1- month ! day ! r> year @ dup 4 / day @ year @ leapYear? if leap-years else years then month @ + c@ + + + + 7 mod ; : ? ( day month year -- ) dow case 0 of ." Sunday" endof 1 of ." Monday" endof 2 of ." Tuesday" endof 3 of ." Wednesday" endof 4 of ." Thursday" endof 5 of ." Friday" endof 6 of ." Saturday" endof endcase space ; 31 1 1883 ? 3 12 1970 ? 25 12 2017 ? 1 1 2018 ? Edited March 21, 2017 by Willsy 4 Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 21, 2017 Author Share Posted March 21, 2017 Source for the algorithm: http://www.stoimen.com/blog/2012/04/24/computer-algorithms-how-to-determine-the-day-of-the-week/ Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 22, 2017 Share Posted March 22, 2017 Cool Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted March 22, 2017 Share Posted March 22, 2017 http://atariage.com/forums/topic/187197-on-a-date-like-this/ 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 22, 2017 Share Posted March 22, 2017 You've got to love Forth Now I'm itching to do a pure software project. I have something in mind, and I think this time around I'm going to use FbForth so I can test it out. 4 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 22, 2017 Share Posted March 22, 2017 The calendar code is pretty nice. Something I have been playing with is creating a Forth layer that is TI-BASIC user friendly. Forth is a chameleon so it not too hard to do, but there would still be the RPN aspect of Forth to contend with and spaces between each token in the source code but it would overlap better with TI-BASIC users knowledge base and expectations. One easy to fix sticky point is the colours in Forth use the machine values 0 to 15 where TI-BASIC uses 1 to 16. One could also do this kind of thing pretty simply in Forth: VARIABLE A$ 32 DIM A$ =" This is a Forth string" A$ PRINT This is a Forth String ok If I created such layer on top of Forth with documentation, would it have some value to the 99ers here? BF Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 22, 2017 Share Posted March 22, 2017 (edited) week.turbo.png week.xb.png http://atariage.com/forums/topic/187197-on-a-date-like-this/ I am fascinated by the semantic density between Forth version and the BASIC program. The creator of BASIC found a way to create a pretty high level language. Consider the PHP example Willsy gave us. function get_century_code($century) { // XVIII if (1700 <= $century && $century <= 1799) return 4; // XIX if (1800 <= $century && $century <= 1899) return 2; // XX if (1900 <= $century && $century <= 1999) return 0; // XXI if (2000 <= $century && $century <= 2099) return 6; // XXII if (2100 <= $century && $century <= 2199) return 4; // XXIII if (2200 <= $century && $century <= 2299) return 2; // XXIV if (2300 <= $century && $century <= 2399) return 0; // XXV if (2400 <= $century && $century <= 2499) return 6; // XXVI if (2500 <= $century && $century <= 2599) return 4; // XXVII if (2600 <= $century && $century <= 2699) return 2; } /** * Get the day of a given date * * @param $date */ function get_day_from_date($date) { $months = array( 1 => 0, // January 2 => 3, // February 3 => 3, // March 4 => 6, // April 5 => 1, // May 6 => 4, // June 7 => 6, // July 8 => 2, // August 9 => 5, // September 10 => 0, // October 11 => 3, // November 12 => 5, // December ); $days = array( 0 => 'Sunday', 1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', ); // calculate the date $dateParts = explode('-', $date); $century = substr($dateParts[2], 0, 2); $year = substr($dateParts[2], 2); // 1. Get the number for the corresponding century from the centuries table $a = get_century_code($dateParts[2]); // 2. Get the last two digits from the year $b = $year; // 3. Divide the number from step 2 by 4 and get it without the remainder $c = floor($year / 4); // 4. Get the month number from the month table $d = $months[$dateParts[1]]; // 5. Sum the numbers from steps 1 to 4 $e = $a + $b + $c + $d; // 6. Divide it by 7 and take the remainder $f = $e % 7; // 7. Find the result of step 6 in the days table return $days[$f]; } // Sunday echo get_day_from_date('31-1-1883'); Edited March 22, 2017 by TheBF Quote Link to comment Share on other sites More sharing options...
Opry99er Posted March 22, 2017 Share Posted March 22, 2017 A BASIC compiler/translator written in Forth, eh? Ears open... Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 22, 2017 Author Share Posted March 22, 2017 week.turbo.png week.xb.png http://atariage.com/forums/topic/187197-on-a-date-like-this/ Wow! I Love that basic program. I'm going to have to translate it Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 22, 2017 Author Share Posted March 22, 2017 Something I have been playing with is creating a Forth layer that is TI-BASIC user friendly. <snip> The thing is, once you learn Forth, you realise it's actually EASIER than BASIC! Especially when you have features such as local variables, which can eliminate stack thrashing completely; especially with my locals implementation, which do not have to be loaded from the stack - they are true local variables. Quote Link to comment Share on other sites More sharing options...
+mizapf Posted March 22, 2017 Share Posted March 22, 2017 The thing is, once you learn Forth, you realise it's actually EASIER than BASIC! Just being curious, as you are obviously skilled in Forth: Can you indeed understand a Forth program from looking at it (of course, if you are not the author)? In that sense, what you just said, is it easier to write a Forth program than a BASIC program, or easier to understand such a program? My programming skills are certainly strongly influenced by object orientation for the last 22 years, so I admit I feel really lost when I look at a Forth program as shown above. (The same would be true for me for functional programming or logic programming.) Quote Link to comment Share on other sites More sharing options...
Omega-TI Posted March 22, 2017 Share Posted March 22, 2017 ...once you learn Forth, you realise it's actually EASIER than BASIC! Now THAT would make a neat bumper sticker! 1 Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 22, 2017 Author Share Posted March 22, 2017 Hi Michael, Chuck Moore (the inventor of the Forth language) describes the Forth language as an "amplifier"; meaning that well designed Forth can look beautiful and almost read like english (or, at least, quite intuitive to understand) whereas badly written Forth can look terrible and be utterly incomprehensible. Forth *can* be hard to understand. The reason is, in most languages you are only directing the flow of the *code* (when certain things are executed, and when they are not). In Forth, in addition to controlling code flow, you are also controlling the flow of *data* because it sits on a FIFO stack. You can of course use variables but the stack is used to manipulate everything. Most of the Forth code that I see that isn't written by me I find hard to understand. There's essentially two reasons: 1) It's mostly from Forth nerds on comp.lang.forth and they actually seem to take delight in posting incredibly obtuse, non-idiomatic Forth code. It's like it's some sort of Forth coder cock-measuring context. 2) See 1 I find my own code easy to understand, but that's probably because I understand my own style! Having said, I find any code that I didn't write hard to understand. I spend a lot of my day job (at the moment) modifying Structured Text code (similar to Pascal) written for control systems. I find it TERRIBLY difficult, and somewhat terrifying. I find that after a while, I begin to get "into the mind" of the programmer, and *that's* when I begin to understand the code. When I understand where the programmer is coming from, and where he's going. Then it begins to make sense. I'm digressing. Forth is a language for writing other languages. So, normally, when you write a (major) program in Forth, maybe as much as 25-30% of it might be code that is associated with defining a domain specific language which the rest of the program would be written. This low-level, domain specific language definition code will typically be low-loevel nitty-gritty Forth code, and quite dense and difficult to understand. However, when the application is written using the domain specific language, the application is often very simple to understand. The word awesome is oft overused these days, but Forth's ability to extend itself, in terms of itself, is really quite awesome and totally mind blowing when you first experience and understand it. For example, I might be writing a game (space invaders) and to put the invaders on the screen, I could define a DSL such that I can later write: : displayAliens on 20 rows 12 aliens per row ; So, this is a word called displayAliens, and, well, you can understand exactly what it does, because it reads like English, but it isn't English. It's Forth. More specifically, the Forth language has been expanded with words such as rows, aliens, per and row, which are not mere subroutines/functions as they would be in other languages, but are now part of the language itself, just like DUP or SWAP or IF etc. The Forth philosophy is very deep, and it takes time to fully appreciate it. It was the best thing I ever did in my personal journey with computing. 1 Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 22, 2017 Author Share Posted March 22, 2017 Now THAT would make a neat bumper sticker! You make 'em, I'll buy 'em 1 Quote Link to comment Share on other sites More sharing options...
Omega-TI Posted March 22, 2017 Share Posted March 22, 2017 You make 'em, I'll buy 'em I think Chris' wife is the person you want to talk to! Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 22, 2017 Author Share Posted March 22, 2017 Harping on more about local variables, look how code can be simplified by using locals. Here's a program to do exponentiation: : ^ ( i n -- i' ) begin dup 1 > while -rot over * rot 1- repeat drop nip ; It's idiomatic Forth. It doesn't use variables at. It does everything on the stack. Because it does everything on the stack, there's a certain amount of stack-juggling (stacrobatics) going on, just moving things into the right place on the stack for the next operation, etc. Being truly idiomatic, it would be written horizontally, like this: : ^ ( i n -- i' ) begin dup 1 > while -rot over * rot 1- repeat drop nip ; But I find that the indentation helps with understanding. There are endless arguments between ninja black-belt snobby Forthers over this issue, which I won't go into here! Let's have a look how it looks in TurboForth with locals (full disclosure: TurboForth's locals implementation is unique to TurboForth (I believe them to be superior)): : ^ ( n r -- n^r ) locals{ n r } set r set n n n * r 1- 0 do n * loop ; No stack juggling. This version will actually execute faster than the idiomatic version because CPU cycles aren't being burned moving things around on the stack. 1 Quote Link to comment Share on other sites More sharing options...
lucien2 Posted March 23, 2017 Share Posted March 23, 2017 I am fascinated by the semantic density between Forth version and the BASIC program. The creator of BASIC found a way to create a pretty high level language. Consider the PHP example Willsy gave us. The PHP example is not exactly the same algorithm. It does not test leap years and the century codes are not in an array but in a switch/case statement. Consider this JavaScript version. Forth: 30 lines of code, 913 bytes JavaScript: 26 lines of code, 778 bytes var years = [ 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 ]; var leap_years = [ 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 ]; var centuries = [ 4, 2, 0, 6 ]; var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ]; function century(year) { return centuries[Math.floor(year % 1700 / 100) % 4]; } function leapYear(year) { return !(year % 400) || year % 100 && !(year % 4); } function dow(day, month, year) { day = +day; month = +month; year = +year; // string to number var yy = year % 100; return days[ (century(year) + yy + Math.floor(yy/4) + (leapYear(year)? leap_years[month-1] : years[month-1]) + day) % 7 ] } function dayOfWeek() { output.innerHTML = dow.apply(null, input.value.split(' ')); } 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 23, 2017 Share Posted March 23, 2017 Yes I noticed that PHP was a very different algorithm. It was the first code I saw on the page Willsy pointed to. The Java code is much tighter and tracks more closely with the Forth version. Thanks! B Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 23, 2017 Share Posted March 23, 2017 (edited) <SNIP> Let's have a look how it looks in TurboForth with locals (full disclosure: TurboForth's locals implementation is unique to TurboForth (I believe them to be superior)): : ^ ( n r -- n^r ) locals{ n r } set r set n n n * r 1- 0 do n * loop ; No stack juggling. This version will actually execute faster than the idiomatic version because CPU cycles aren't being burned moving things around on the stack. Now if those locals took spare registers instead of space on the stack what would happen? (I am still jealous of GCC) :-) Here was some code I thought code be used to allocate register variables in machine Forth as long as you have the spare registers contiguous from 1 to n. NEW.REGS would have to RUN by the Forth word LOCALS in order to free up a new batch of registers for your sub-routine (WORD). variable reg# \ holds the next available register : new.regs ( -- ) 6 reg# ! ; \ INIT the allocations: my system has 6 free registers from R0 to R5 : reg.allot ( -- n) reg# @ 1- dup 0< \ check if have any left abort" no more registers!" \ abort if we don't dup reg# ! ; \ return the available register and store in REG# : local ( -- <text>) create reg.allot , \ compile time: create a named number that is allotted register does> @ ; \ run time: fetch the register number when the name is used in a program Edited March 23, 2017 by TheBF 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 23, 2017 Share Posted March 23, 2017 (edited) Hi Michael, Chuck Moore (the inventor of the Forth language) describes the Forth language as an "amplifier"; meaning that well designed Forth can look beautiful and almost read like english (or, at least, quite intuitive to understand) whereas badly written Forth can look terrible and be utterly incomprehensible. Forth *can* be hard to understand. The reason is, in most languages you are only directing the flow of the *code* (when certain things are executed, and when they are not). In Forth, in addition to controlling code flow, you are also controlling the flow of *data* because it sits on a FIFO stack. You can of course use variables but the stack is used to manipulate everything. Most of the Forth code that I see that isn't written by me I find hard to understand. There's essentially two reasons: 1) It's mostly from Forth nerds on comp.lang.forth and they actually seem to take delight in posting incredibly obtuse, non-idiomatic Forth code. It's like it's some sort of Forth coder cock-measuring context. 2) See 1 I find my own code easy to understand, but that's probably because I understand my own style! Having said, I find any code that I didn't write hard to understand. I spend a lot of my day job (at the moment) modifying Structured Text code (similar to Pascal) written for control systems. I find it TERRIBLY difficult, and somewhat terrifying. I find that after a while, I begin to get "into the mind" of the programmer, and *that's* when I begin to understand the code. When I understand where the programmer is coming from, and where he's going. Then it begins to make sense. I'm digressing. Forth is a language for writing other languages. So, normally, when you write a (major) program in Forth, maybe as much as 25-30% of it might be code that is associated with defining a domain specific language which the rest of the program would be written. This low-level, domain specific language definition code will typically be low-loevel nitty-gritty Forth code, and quite dense and difficult to understand. However, when the application is written using the domain specific language, the application is often very simple to understand. The word awesome is oft overused these days, but Forth's ability to extend itself, in terms of itself, is really quite awesome and totally mind blowing when you first experience and understand it. For example, I might be writing a game (space invaders) and to put the invaders on the screen, I could define a DSL such that I can later write: : displayAliens on 20 rows 12 aliens per row ; So, this is a word called displayAliens, and, well, you can understand exactly what it does, because it reads like English, but it isn't English. It's Forth. More specifically, the Forth language has been expanded with words such as rows, aliens, per and row, which are not mere subroutines/functions as they would be in other languages, but are now part of the language itself, just like DUP or SWAP or IF etc. The Forth philosophy is very deep, and it takes time to fully appreciate it. It was the best thing I ever did in my personal journey with computing. I will echo the language creation concept. I always say that I stop programming in Forth after this first page of code. Years ago I read an article where a guy wrote code to "Menu Drive the 8250 UART" in Forth. It was a menu on the screen where you pushed 1 to do X, 2 to do Y,3 to do Z etc. All this so you could configure the $!%!#$ RS232 ports on a PC. I kind of lost it when I saw it but it prompted me to write a reply article that was published. I created the following Forth words: COM1: COM2: BAUD BITS PARITY ODD EVEN NO STOP-BIT Ya you get it. So instead of pile of BS menus, you could now type at the console -OR- use in your program: COM1: 9600 BAUD NO PARITY 1 STOP-BIT etc... You don't actually program in Forth. It's too stupid. :-) (primitive) You make what you need and then program in that. B Edited March 23, 2017 by TheBF 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted March 23, 2017 Share Posted March 23, 2017 ... In Forth, in addition to controlling code flow, you are also controlling the flow of *data* because it sits on a FIFO stack. ... Not to get in the way of your most excellent dissertation, but the data stack is LIFO. ...lee Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 23, 2017 Share Posted March 23, 2017 The master has spoken. You have a gift Lee. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted March 23, 2017 Share Posted March 23, 2017 Thanks. Not everyone appreciates nitpicking, but I do it anyway. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted March 23, 2017 Share Posted March 23, 2017 Harping on more about local variables, look how code can be simplified by using locals. Here's a program to do exponentiation: : ^ ( i n -- i' ) begin dup 1 > while -rot over * rot 1- repeat drop nip ; It's idiomatic Forth. It doesn't use variables at. It does everything on the stack. Because it does everything on the stack, there's a certain amount of stack-juggling (stacrobatics) going on, just moving things into the right place on the stack for the next operation, etc. Being truly idiomatic, it would be written horizontally, like this: : ^ ( i n -- i' ) begin dup 1 > while -rot over * rot 1- repeat drop nip ; But I find that the indentation helps with understanding. There are endless arguments between ninja black-belt snobby Forthers over this issue, which I won't go into here! Let's have a look how it looks in TurboForth with locals (full disclosure: TurboForth's locals implementation is unique to TurboForth (I believe them to be superior)): : ^ ( n r -- n^r ) locals{ n r } set r set n n n * r 1- 0 do n * loop ; No stack juggling. This version will actually execute faster than the idiomatic version because CPU cycles aren't being burned moving things around on the stack. These ideas are great, Mark, but your code will not work as is. The “stackrobatic” word is missing over swap before begin . The “locals” example gives n^(r+1) instead of the desired n^r. It can be fixed by removing n * before the loop and enclosing the loop in r 1 > if ... then . Neither example handles r = 0, which can be managed with : ^ ( i n -- i' ) dup 0= if 1 else over then swap begin dup 1 > while -rot over * rot 1- repeat drop nip ; : elseof compile dup [compile] of ; immediate : ^ ( n r -- n^r ) locals{ n r } set r set n r case 0 of 1 endof 1 of n endof elseof n r 1- 0 do n * loop endof endcase ; ...lee, the nitpicker! Quote Link to comment Share on other sites More sharing options...
Willsy Posted March 23, 2017 Author Share Posted March 23, 2017 Ah I should have checked more closely! I did have code for checking for 0 and 1 but removed it when posting for brevity. Of all nits worth picking this was surely one of them! Thanks :-) Is good to be talking about Forth again. By the way, I made some significant improvements to the locals implementation in TF last night. Have a look at the locals page on the website. Also updated the online help. Need to update the blocks disk. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.