Ah, classic! For a topical variant from back when I was in high school: Q: How many Pentium designers does it take to screw in a lightbulb? A: Hmm... I ran a simulation and got 0.9999997 Pentium designers...
Get you another one. I found one on Ebay for like $100 and got an svideo connector to hook up to a “good enough” 720P flat screen and it looks pretty darn good. Cheap 1541s and 1571s out there too. BC quest for tires is still a blast and these experiments the author posts are fun to try.
Agreed drop dead. I now have 3 new C64s...a redone NTSC to Pal conversion machine, a C64 Reloaded MKII machine and an Ultimate 64 in a new C64C case. Doing some programming again as its been decades doing anything in 8 bit and the raw power and control you have is really liberating.
Fascinating, I owned the original c64 when it first came out in the UK, I was a teenager then. Lol I’m over 50 now. I wish I had kept it as I would love to have tried these quirks out. Also I really enjoyed poking things into the screen. I was never a programmer but I was amazed at the graphics and music people got out of the computer back in the day. Looking back the SID chip was my favourite audio chip. Your videos have brought back great memories, I thank you for that. Keep up the great and interesting work.
Update: The storm going through Minnesota and Wisconsin may prevent me from reaching the Midwest Gaming Classic this weekend! So... have fun without me, maybe! ERRATA: I (and the C64) made a mistake in the 9^X example at the end: by 9^9 the rounding error has increased to a whole number, so the number displayed is one greater than it should be! Thanks to the commenters who pointed this out. And here's this episode's index: 0:00 Intro / Midwest Gaming Classic 1:44 REM Shift-L bug 2:38 ?””+-0 crash 3:46 ?0+””+-0 hard crash 4:31 Hit Stop+Restore keys, then: POKE 781,96 : SYS58251 “screen saver” 5:40 M FFF6 Robert Russell / Bob Yannes 7:11 350720 crash 8:36 A=A+0.01 float rounding error 11:07 9^X exponent float rounding error
Watching this from the upper michigan area and its horrible here. Storm is kickin good. White out. Great episode by the way. My fav bug is the adding bug. Wow! Thats a common thing to do add by hundredths.
Some more floating-point weirdness: try to print the value 946.352946. Just PRINT 946.352946. The result won't be what you would expect. And that number wasn't even specially constructed to cause this effect, it's the exact number of milliliters in a (U.S. liquid) quart.
There was a pretty long post about the BASIC floating point math on comp.sys.cbm(?) back in the day. For those interested it is preserved in issue #12 of the famous C= Hacking magazine.
:) The floating-point format the C64 uses is capable of representing 9^9 exactly, so it must be rounding errors in the exponentiation routine itself. Interesting, but not really surprising. Floating point is an invention of the devil. ):->
indeed... the c64 is a full number off ... it's also on par with the deviation that is building up on the other powers of 9.. as you can see for yourself the number is always getting bigger, so at a certain time it just has to cross the comma... my guess is that once u use any power higher than 9th it's always more than a whole 1 deviation (probably 1, 10, 100, ... with 9th, 10th, 11th power) I don't have a c64 anymore so i can't check by myself
This type of error can be found on just about any high-level computer language on any type of computer especially those written by Microsoft. It still happens today even in Visual C++. It doesn't seem to occur if you choose to implement BCD math routines however. I had many an argument with Mr. Gates about his math routines back in the day. I remember one instance where a customer of the place I worked for in the '80's came in complaining that there was something wrong with the computer because he balanced his checkbook and the computer was a penny off. All I could tell him is buy better software.
THANK YOU for putting up effort in all these C64 Videos!! The C64 is often considered an old and simplistic homecomputer, but it aint. it contains all kind of wonderful engineering, tricks and wizardry that even by today standards amaze me. I bet the C64 will still live on even when we are all gone.
Hi Robin! Tremendous work! Thanks for taking the time to share these experiments and tips. I have thoroughly enjoyed each video, and have a new appreciation for my childhood computer of choice! I have a "thec64 mini" now, but hope to pick up a real c64 soon. My 3 older kiddos have been tinkering in C64 BASIC, and I'd love to put a real breadbin or c64C in front of them.
That's great, I've had some of my kids do a bit of C64 BASIC programming too. The full-size THEC64 is getting closer to completion so that might be an option too. It apparently will boot directly to BASIC!
Bugs in the BASIC interpreter! I'm surprised there aren't more. I've spent most of my programming career working with packed and zoned decimal numbers, so floating point has always fascinated me.
2:39 I use "?" as an alias for a command-line calculator program on my Linux desktop, since I got used to having that power on the Commodores. 4:27 When a VIC-20 was my only computer, I made a tool out of a paperclip to short two specific pins of the User Port together to do a hardware reset. 5:07 Is there an actual pattern to the question marks? 10:04 The unexpected thing is that BASIC doesn't have GREATER problems with floating-point round-off. 10:57 Even a value like the "1.23" that displays correctly might not be quite right internally, so you can't even count on the equality of values that look the same. BASIC stores LOG10(2^32) = 9.63 decimal digits of precision into floating-point variables but only displays 9 digits. However, you can always count on the equality of integer values where all intermediate values were intergers. E.g., A=A+1 will always be exactly an integer if A starts as an integer (unless it overflows ±2^32-1). www.c64-wiki.com/wiki/Floating_point_arithmetic 11:19 Exponentation, even to the power of an integer, is calculated using the mathematical identity b^x = EXP(x*LOG(b)). It doesn't use open loops (e.g., executing 1.001^10000 as 1.001 times itself 10000 times). The EXP/LOG method takes a constant amount of time using series expansions that involve multiplications, additions, and fractional constants that can introduce floating-point round-off errors. www.c64-wiki.com/wiki/EXP 12:27 The 9^9 case didn't correct itself - it's off by a full integer! On a calculator with more precision, 9^9 = 387420489.
Re: paper clip trick. Ha I totally remember that. I used to do that while playing games. Then I ran a program that I wrote which would iterate through all the possible locations for graphics memory. If you were lucky you could get a "screen shot" of your game that way. I even wrote it out to disk using run length encryption (which I thought I had invented but quite obviously didn't).
As for the floating point error, the exact moment it happens depends on the particular floating point format. Commodore BASIC uses 40-bit Microsoft Binary Format, while modern processors use 32-bit and 64-bit IEEE 754 formats. In particular, when adding 0.01 with 64-bit IEEE floats, you will get an error as soon as 0.060000000000000005. I think it depends on where you cut the binary expansion of 0.01: In 40-bit MBF the next two bits after the cut are 00, in 64-bit IEEE it's 10, so the error is more noticeable and accumulates sooner. As for 10remL, I did some experiments and it seems like the graphics characters are turned into various BASIC tokens, with shift-L being probably the only one that causes the error. The formula between the PETSCII values and token numbers seems to be non-trivial and I'd love to see some more info about that. The crash caused by adding string to numbers is also interesting. The behaviour is non-deterministic: the same expression can either do nothing, cause a break, cause a syntax error, or crash the machine completely. Also a very interesting topic to explore, it requires digging into BASIC's expression parser though and it might be complicated.
When BASIC tokenizes the REM statement, Shift-L is converted to $CC. BASIC tokens all fall in the range of $80 to $CB (except for pi, which is $FF). Now you see why Shift-L causes the error. It's referencing a non-existent token, and the interpreter bails with a SYNTAX ERROR. (I have no idea why Shift-N thru Shift-Z don't cause the same error.)
@@SpearM3064 I noticed that shift-K turns into GO, which is $CB, but shift-M turns into $81, which is FOR. No idea why it skips $80 It then follows the sequence until shift-minus ($7D) which turns into ON ($91), and the next PETSCII character is π. I haven't analysed exactly which tokens are generated after that, the pattern seems a bit more random though.
@@vytah Interesting. To be honest, I had a Commodore 64 for about a decade (and in fact, I still have two of them, plus a 1541 and a 1541-II, in my closet); I don't know why I never analyzed this myself in all that time. Thanks for doing the research!
Hey there! I groggily clicked on your video this morning mistaking it for one by another c64 and BASIC enthusiast whose name begins with "8-Bit". And I'm really glad I did! Subscribed and will be hanging around for a while. Keep up the great work! Cheers.
I'm glad you clicked on it too :) Thanks for subscribing. I've actually been on that other guy's show a few times, most recently in his "dream computer" episode in a couple short segments.
You are the Bob Ross of Commodore adventures. I mean that in a very supportive way. Thanks so much for bringing back the memories of my teen years. Your videos are very intriguing!
Haha, I never thought of it like that, but you're absolutely right. I can watch Robin's videos all day long and never get tired of them. I used to watch Bob Ross for hours as a kid the same way. Just something "good" about the whole process. Can't explain it, but it works!
a tip i always give about math with floating point numbers is to either use numbers like 1 / (2^n) (because those numbers fit perfectly into floating point numbers and are completely immune to Floating point errors). or avoid decimal points unless printed out so instead of: 0 PRINT X : X = X + 0.1 : GOTO you would do: 0 PRINT X / 10 : X = X + 1 : GOTO the more digits after the decimal point you want, the more you digits you have to add onto the 1 to divide by. so 1 digit after the comma you have to divide by 1 with one 0 after it. so 10. 3 digits (0.125 for example) would need to be divided by 1000, and so on.
Proxy do you maybe mean numbers like 1/(2^n) instead? As is, it seems like you're saying 1/9 will fit perfectly into a binary representation but that's certainly not the case. Cheers!
Hi Robin it's always a pleasure to watch your videos. I have found another FP bug, longtime ago.. try to print the sin(pi) and you have not 0 but a fp number : 3.whatever times 10 powered to -9 . Another rounding error. There are many.. !
In your very first example with the REM shift L, I seem to remember some basic programmers using this as a sort of rudimentary copy protection way to keep people from looking at their code. Of course if you knew the LIST and line number plus one you could get by it but I also remember some folks loading lines of code with this sequence at the beginning so it would take a while to find the line you could list from. Thanks for sharing!
Yes, I remember seeing this when I was a kid and being bewildered by this. There are other REM tricks similar to this, I'll probably make a whole video about it unless someone else makes a good one about it first :)
@@8_Bit One trick I used involved a memory editor. I would create a REM statement with about six blank spaces and a Shift-L. Then I would go in with the monitor on my FastLoad cartridge and replace the spaces with $14 (DEL) characters. So when you LISTed the program, all you'd see was the SYNTAX ERROR. If you were paying attention, you might be able to see the line number and REM statement for a fraction of a second before it was deleted. The idea was that it would be harder to figure out what the "line number plus one" was. For the most part, I never bothered "protecting" my programs that way, though.
Re-watching this video years later... and I just ran that A+0.01 program on my C64. If you let it go for a while, it gets stranger and stranger. Sometimes the rounding error increases over time, other times it decreases, and every now and then it starts printing correct values again. By the time you get to what should be about 55.55, it's actually so far off it shows 55.55001, which is a pretty substantial error.
I think the floating point problem could be a good case for using integer variables if you need to do calculations and then compare. I can't recall if t he C64 had a function to limit the number of decimal places or if you had to use your own math to round it up properly? I do recall that trick with the REM and some other one I forget now, being used in some commercial BASIC games (I seem to recall Strip Poker used some trick like that) to prevent you from listing the program. Throw one of those between each line and you have a headache listing. I forget what they actually used. My favourite by far was the trick where you relocated where the PRINT command prints to so you could PRINT out sprites, or sound effects etc... no reading and poking of data. It acted like a large, multipoke, where you set a range of memory. What you print being the characters that represent the values you want. It is an amazingly powerful trick to use. It even reduces the size of your program as you don't need all those data statements and a FOR->NEXT loop etc. POKE209,0:POKE210,212:POKE211,0:?"@@@@@@@@@@@@@@@@@@@@@@@@@"; The @ is zero on the C64, so this particular print clears out the first 25 memory locations for the SID chip, effectively clearing it in one go. You poke the low byte into 209, the high byte into 210, so this prints zeros starting at 54272 + the next 24 memory locations. So just figure out the high byte/low byte, poke them into 209 and 210, then print there. I forget the memory location for sprites and what each sound location does, but look up the SID memory, 54272, what it does, change it and the following locations in this print string and make a sound effect! I forget the exact numbers, but you can change those pokes to point to memory for SPRITES and use the same trick, each character is the number you wish to poke in that memory and you can create a sprint with one print. Amazing trick I loved back in the day, at least until I started to program in 6510 assembly anyhow.
Yeah, to round off you basically have to do some multiplication and use the INT() function to truncate. No built-in easy function for it. I was just reminded of that PRINT to POKE trick, you use location 648 to change where BASIC thinks screen memory is. Somebody left a comment with a use of it to do that speaker click trick at 900+ Hz, way faster than the fastest we had achieved with the POKE methods.
To manually overcome decimal rounding errors you multiply the number you are working with by something like 100 or 1000 or 10000 (depends on the precision you want), do the math, the rounding error, if it occurs, always happens to the least significant number, make it an integer to drop any remaining decimal then back into floating point, and divide it by 100 or 1000 or 10000 (what ever you used to multiply). Dividing by 10, 100, 1000, etc, simply moves the decimal position and has no rounding error. This method also prevents the accumulation of errors. C-64 has no PRINT USING "00.00" command or X = Float Using "00.00" format, but in some languages these only mask the rounding error and can accumulate, unseen, over repeated operations.
If you want to do calculations then compare with floats, the usual approach is to test if it's within some small value of the target, rather than equal to it. A replacement for "if (x==0)" (supplied in C, given I've forgotten BASIC syntax): #define epsilon 1e-6 /* do your calculations here */ if (abs(x) < epsilon) { /* do stuff for when x==0 */ } If you want to test against a non-zero value, you could subtract x from it first using abs(val-x) instead.
absolutely love these kind of videos. Please keep em coming and please don't use any kind of music or whatever in the background, the silence just helps me getting absorbed into the subject matter and the nostalgia of those days
great video. I will be creating a video on my channel to run some of these math oddities on the Atari 130XE Basic to see how it handles them ( or mishandles )
Back when I was programming dBase III+ to output to laser printer, I'd get odd offsets due to rounding errors The way I found to correct it on the fly with minimal interpreter overhead was to cast the result to string, then back to number so the value would look like VAL(STR()) BASIC 2 it would be VAL(STR$()) . I imagine that that sort of nested function would be pretty slow, based on what you've shown previously. Edited for some blind stab at an 'English as a first language' vibe. :D
Oddly, the biggest culprit was something like 125/5 (from memory - the notes are in an R-Kive box in the attic, possibly labelled "1989 - Programming") that gave 24.99999999999999999... to whatever the precision was in dBase. I remember the Ashton-Tate support guy saying 'That's not possib... bloody hell...' so it wasn't 8088 IBM clone specific.
The results you got from poke 781,96:Sys58251 triggered a very old and rather vague memory from way back in the early '80s when I had my original C-64. I had stumbled across a poke that caused the C-64 to go crazy, changing screen/border colours, sometimes showing corrupt characters on the screen and triggering a shower of either exclamation marks or question marks (I forgot which), rather like the example shown here. Eventually after a random amount of time it would stop, with the computer frozen. I would get a slightly different effect each time. Sadly I can't remember the poke, though I think the first digit of it was 7. I tried to poke around with my present C-64, but have been unable to find it again.
For anyone interested in getting a little more info about floating point errors, this Computerphile video featuring Tom Scott does a really good job of laying everything out: th-cam.com/video/PZRI1IfStY0/w-d-xo.html
TI 99/4A didn't have the floating point problem. This was the only thing its basic had that was so much better than any other home computer. It had BCD coded floating point with 13 digits precision and 10^-99 to 10^99 range. It essentially had the math routines used in TI calculators. What a bad surprize it was when I switched to Apple II later on and I discovered how bad binary floats are in reality.
Because TI99 probably used more bytes for floating numbers. Standard is 4 bytes, and 8 bytes for double precision, there were also 48-bit implementations (6 bytes).
@@cbm80amiga yes, TI took 8 bytes (13 BCD nybbles mantissa, 2 BCD nybbles exponent, and 1 nybble for the signs of exponent and mantissa. remains 2 bits unused or used for internal stuff. TI never was very open with their code. Applesoft used 5 bytes, 4 for the mantissa and 1 for the exponent, giving 31 bit for the 1-complement encoded mantissa and 8 bits 2-complement exponent.
@@cbm80amiga The impoortant thing was that they used BCD to encode the numbers, which avoided the rounding errors we see in this video when converting to a string representation. Pocket computers from Sharp and Casio also used a very similar BCD encoding of floating points and except for IBM big iron machines, these decimal formats have disappeared and it's really a pity as they had some real advantages over the usual binary floats.
floating point granularity is why you use >= Never used a c64 before because it was just a tad before my time, however I grew up on qbasic which was essentially the same just with up to 640K of memory. I was fortunate enough be be a part of an online community of qbasic/quickbasic/qb45 fans in the mid 90's where we challenged each other with programming contests and shared tutorials and new discoveries. After a few years, maybe 5 or so, qbasic and variants was getting harder and harder to run on the newer operating systems so a group of the fans got together to write a new compiler that would run on any linux or windows os's but still keep the old syntax and add some new ones plus full api support etc. It ended up being called FreeBasic www.freebasic.net/ and I still use it from time to time today.
After 4 years of learning C-64 BASIC, I was forced to move over to ABasic when the U.S. Navy began putting IBMs in all office work spaces in the late 80s. That eventually lead me to QBasic and also QDOS. I still have QBasic that only runs in DOS Box, but the compiled programs from QBasic can be run (usually) from a console window. About the only thing that doesn't work properly, if at all, are POKE commands. Windows Vista and above will not allow direct memory access, or it's a problem with QBasic using absolute addressing on a system that uses relative addressing (?) QDOS, by the way, was a DOS plugin that added about 100 commands to DOS that could be put into a fairly complex DOS shell. There were entire games written that ran within a DOS shell. I never found the time to write much other than menu and program launching shells for my computer illiterate wife, but was always amazed to see the capabilities of IBM DOS that 99% of users didn't know existed.
With the shift + l trick you can actually do a lot more than that.. you can execute screen commands too like the reverse heart to clear the screen and you can change the colours of the text... I first learned about it in an old basic game called the secret of bastow Manor and then years later I read in a computes gazette about the shift trick showing how to change the text colour and I realised you could do a lot more with it including cursor movements and more
Still found the input parser fascinating, how flexible basic is plus the kernal routines in less than 40K .... You can even move the cursor to any part of the screen and press enter to excecute again. Rounding issues are all around, probably more noticeable in the C64 because is a SW based floating point unit with not much room to spare. For a personal home micro, is stunning. Always enjoyed the C64 as a console, but never put its potential to good use.
Nice to get a face to go with the voice, Robin. I was beginning to wonder if you were Thing's long lost "brother". You know, the other disembodied hand from the Adams Family... since hands usually come in pairs 🤜🤛 - Only kidding 😁 I love finding videos about stuff I don't know. But as you can imagine, this gradually becomes harder and harder, or at least when it comes to the C64... But somehow you're able to just keep the interesting videos coming 👍 I wonder to what extend Commodore fixed these bugs in the C128's basic. I have also fairly recently stumpled upon the Basic 8 ROM and floppies, which I didn't know even existed. Seems to mainly be added support for doing graphics on the 80 columns display and probably works best with a RAM upgrade on the VDC, which I have. I do love hearing about the C64, but I also think the C128 gets a bit neglected on the web. Or at least when it comes to programming. Maybe you could venture into that stuff, once you run out of material about the C64? - it would be great to hear about the C128 at your level of thoroughness.
Thanks Carsten! Sometimes my second hand makes an appearance :) And I have appeared in full corporeal form at the end of the "The Extra Spaces in Commodore 64 BASIC Errors" episode. It may not be a coincidence that's my most down-voted episode. Though maybe it's because I'm singing and playing ukulele: th-cam.com/video/ZU7XZleSCAc/w-d-xo.html My list of episode ideas is creeping towards 200 items now, so I hope to keep making interesting videos for a long time! But yes, it'd be great to explore C128 mode more and I should get to that eventually. In the meantime, check out Nybbles and Bytes' channel for some C128 focus. Basic 8 is very interesting; I read about it a lot back when it was released, but never did try it myself. I'll put it on the list of ideas, thanks :)
Ooh, I'm all over Nybbles and Bytes... Impatiently waiting for the next video like a 5 year old for Christmas. Speaking of... I did actually watch that video and found it quite odd, that I have never really taken notice of those extra spaces. But I apparently didn't get all the way to the end of it. Getting older I seem to get more easily distracted and sometimes struggle to keep my focus, so that's not on you. Anyway, watching it again now, I didn't find your singing that bad. I mean the music industry often puts out songs these days which are extensively more horrible 😉 I have a lot of old retros, but not all of them Commodore. Got 3 C128's of which I have decided to keep 2 of as original as possible, or at least on the outside. One of them has now gotten a problem with the character ROM, which I haven't quite sorted out yet. The third was a really sorry looking thing I rescued from eBay, advertised as being non-functional and for spare parts only. So I decided to allow myself to go completely nutz with modding that one. I have mended the broken, scratched and discolored cabinet and given it a crazy multi-layered "rogue-red" paintjob. Much like the ones people put on their cars, which changes color depending on the surrounding light. I have fixed its guts, so it now runs again and did a NTSC to PAL conversion on it in the process (I live in Europe). Added some switchable JiffyDOS ROMs and a Servant/Basic 8 ROM to the U36 Socket. Thinking about making an adaptor and putting an EPROM in twice the size, for maybe a GEOS128 ROM and something else. It also has gotten a DualSID mod now with a 6581r4 and a 8580r5... the dual-mono stereo-effect just sounds awesome.... check it out: th-cam.com/video/-cEuCG1C-yg/w-d-xo.html I really want to do a memory upgrade on it... say to 256 or 512 KB. But it is quite hard to find any easy to follow documentation on how to correctly go by adding memory to the system. Having to distill practical how-to instructions out of complicated in depth technical explanations and diagrams from a PDF on the screen, it just seems to collide really badly with my focus issue these days. The only videos I do manage to find on the subject are of people proudly showing off their spaghetti-nightmare-wiring with a shaky video feed off their smartphones... Anyway, I don't know, maybe you know of someone who has experience with that sort of thing. If you would like to see the red Ferrari looking beast in action there is another link below. It also shows off the twin monitors I have build and modded for it. They used to be VGA-only, but I just swapped out their electronics with two V56 universal LCD TV controller boards. Doing the paintjob on the C128 ended up being such a nightmare to get through, that I haven't yet fully recovered enough to do a black paintjob on the keycaps or even the frame for the dual monitors yet... But this former scruffy looking C128 really is getting quite spoiled, I think 🙂 th-cam.com/video/DS-xRFz3F4g/w-d-xo.html
@@8_Bit I my case it has become a real disability, brought on by decades of excessively over-stressing my cognitive abilities, before finally crashing. The lesson that stress is something you should take very seriously, I guess I had to learn that the hard way. I used to have what I thought to be a dream job, working in a small company programming customized plugins for financial and bookkeeping applications. But it has become increasingly harder for small businesses in software development to survive over the last many years. Unless I actively make a constant effort to remind myself that "this is what you are doing right now", then my attention just seems to drift and repeatedly flicker left or right, without me even noticing it. Doing something where I use my hands like wood-, metalwork or electronics, something where there is a real physical object in front of me, seems to make it easier to localize my focus. But I can be working on one thing, then have to go to the toilet and completely forget about it, then start on another thing, get distracted in another way and start on a third thing… even with the first 2 just a few feet away… and before I know it my workspace and living room is completely cluttered with a lot of haft finished projects and tools spread out into all corners. That is indeed how I end up finally realizing that I’m doing it, because of some in the moment much needed tool that I just can’t seem to find. It feels a bit like living with an annoyingly careless and really messy flatmate, except this one I cannot just kick out. Seeking peoples pity or sympathy is not really my thing, or I don’t believe so. It is just everybody seems so focussed on maintaining their physical health these days and you really need to be as much aware of your mental health too or you might just end up losing something you always thought to be a defining characteristic of your personality. I might also still be a bit traumatised by it all and kind of feel an urgent need to send out some message. But I have now also rediscovered my love for doing electronics and using my hands… and that is kind of a big deal and quite a positive thing too.
@@Zhixalom Sorry to hear that, but I'm glad you're finding some ways of coping that are positive. It's good you're mentioning it, as I've been noticing similar (but more mild) behaviours in myself, and what you've said helps bring it into focus for me. Thanks for the reminders.
Wow, these are really weird; thanks! The ones I'm most fascinated by are where you can freeze the computer just by entering some too-big numbers in direct mode!
I don't know if this counts as a c64 glitch, or just a basic weirdness. But. There's a small program on p53 of the c64 user manual, which when i modified it and fed it to BASIC on the schools rm nimbus pc. The entire network went haywire, tons of beeping, the dot matrix printers spewing random characters at high speed. It caused our IT teacher to panic and cry. This was not my intention, just a hilarious side effect. Typed it out had run command ready, switched off monitor, hit rtn just as we were leaving the classroom. All i did was to replace the + in line 20 with a * (this was what caused the network seizure) and changed the 1 at the end of that line with an 8. (I don't know if this had any bearing on the outcome) if anyone has an rm pc from 89/90 you can try. Though any machine running basic could perform this meltdown. I never tried this on the 64 itself however. ================================== "Wise man say, C, Very important Without it we have only BASI OBAL And PASAL"
long is not really wrong in the context of computer numbers because in the case of integers the std (short) signed int ranges from -32768 to 32767, unsigned goes from 0 to 65535 and then you have long integers-2,147,483,648 to 2,147,483,647 (obviously in 32 bit computers)
As a programmer I've had to deal with the fun of floating point library rounding errors many times. Any idea if these rounding errors are consistent across the various versions of Commodore BASIC or is it more a factor of the 8/16-bit arithmetic used by the processor? Luckily as a kid I didn't do any floating point math (that I recall) on my VIC-20 :-)
It's a factor of the exponent/mantissa format used by their version of BASIC. Two bytes (16 bits) for the exponent, five bytes (40 bits) for the mantissa. The entire Commodore 8-bit line and the Apple II line (running Applesoft BASIC) have the same rounding errors, because their version of BASIC derives from the same Microsoft core. The Atari 400/800 does NOT have the same rounding error, because ALL numbers (integer or floating point) are represented in BCD (Binary Coded Decimal). On the negative side, this means that longer numbers take more memory. On the plus side, no rounding errors!
@@SpearM3064: Commodore BASIC floats have an 8-bit exponent and a 32-bit mantissa. Atari BASIC would still have rounding errors, just not decimal rounding errors. What is 1/3*3? If you have exactly 10 decimal digits, 1/3 = 0.3333333333 and 1/3*3 = 0.9999999999.
@@csbruce Well, yeah, Atari BASIC had to draw the line somewhere. If you have a repeating number like 0.33333, you don't want to fill your entire memory space trying to represent the number. I don't have enough experience with Atari BASIC to know how many significant digits it kept.
@@SpearM3064: Even if you filled the entire memory with 0.33333…, the stored value would still be slightly off. According to a broken web page I found, Atari uses six bytes to represent a float, including one byte for the exponent and sign in binary and five bytes for the 10-BCD-digit mantissa. It has an odd normalization practice where it only insures that the most-significant BYTE of the mantissa is non-zero, I guess to avoid bit-shifting the BCD digits between bytes. Of course, this will introduce extra "wobble" into its true precision. www.retrocomputing.net/parts/atari/800/docs/atari_os/atari_os_user_manual_08.htm
@@csbruce One of the programmers who helped write Atari BASIC and Atari DOS used to write for COMPUTE! magazine. If I knew how to get in touch with him, there are so many questions I'd love to ask him. Not because I want to learn more about Atari BASIC, but because I'm curious about the reasoning behind some of the decisions they made. The normalization practice is not the only odd thing Atari BASIC does...
Microsoft fuzzy floating point numbers: The following square root calculations give skewed results. ? sqr(25)-5 1.86264515e-09 ? sqr(9)-3 9.31322575e-10 This is apparently a problem that many Microsoft BASIC implementations had. There are other examples.
No one has answered the 'REM bug" in a year so I thought I'd look into it. This is not an explanation of the BASIC interpreter's listing routine but a hint as to what's triggering the unusual behavior. First; in a BASIC line if any character is within quotes and not reversed, it is taken as a literal character to be printed to the screen. Reversed characters inside quotes are printing (escape) commands. B; any shifted character that is NOT within quotes gets "tokenized" by adding 128 to it's petskii character number. Next; [shift] L gets tokenized to $204; "L" = petskii (76) + 128 = 204 Lastly; $204 is the BASIC token for "Syntax Error" (ref: Computes Programming the Commodore - The Definitive Guide; pp 143, table 6-1; Internal Storage of BASIC Bytes) Strange that this has a token since "Syntax Error" is not a BASIC command you can use in a program. Most Lastly; The reason attempting to list the token for "Syntax Error" actually triggers an immediate mode Syntax Error remains to be investigated.
Yup, it's not a hardware limitation or anything -- you can see it just by evaluating an expression like "0.1 + 1 - 1" in Python. It's part of the price paid for the floating point representations we use. Some languages like Haskell include rational arithmetic (i.e. fractions) which don't suffer from this.
Hi Robin, I'm watching this in July 2019 months after the Wisconsin convention (hey, that's the beauty of TH-cam) but you say in the intro you were heading down from Canada. With Canada being the second largest country in the world, where in Canada? If it's a privacy issue, no problem. I've just subscribed and started binge watching some of your C64 and 6502 videos, great work! I'm going to hazard a guess based on accent... Sault St Marie? Regardless, keep up the great content! Your channel is a retro-blast and despite thinking I've mastered 6502 asm and the C64 world, I've learned some great little tricks so far! I was happy to see that these quirks "work" on Vice C4 Emulator (except the "screen saver" one) as well as my C64!
Good guess! I'm in Thunder Bay, "just" 8 hours west of Sault Ste. Marie. I'm pretty sure I mentioned it in one episode back in January or February when we were starting the Thunder Bay Retro Computer Club. Thanks for watching and commenting :)
It seems to be a problem with the exponent operator itself. In the new episode I just released, (called "Commodore PC 50-II") I use a loop with multiplication and it comes up with the correct answer without any rounding errors.
Interestingly, those two Commodore BASIC bugs (PRINT ""+-0 and PRINT 0+""+-0) also crash Applesoft BASIC, which isn't too surprising given they are both based on the same Microsoft code. In the case of Applesoft, those two statements cause a bomb into the monitor (meaning a BRK instruction was executed, as theorized in the video). The first statement caused a break at $F4 (zero page) initially, which is rather weird. When I returned to BASIC from the monitor and typed the same statement, it caused a break at $208, which is inside the input buffer itself where the line typed is stored. So somehow the BASIC interpreter is jumping to addresses very low in memory. So perhaps either the stack or the CHRGET subroutine in zero page is getting corrupted, or perhaps the interpreter is looking up an address in a table and the index is too high, or something along those lines. It would be interesting to actually do a trace of the code in an emulator to see what is actually going on.
We had one with ;;;;;;; if I recall, you could write a very short print program with goto. Not sure the exact program now but the result was a screen of flashing strobe colors.
When you were doing that Luke incrementing incrementing the floating Point by 01, did you ever end up seeing a pattern in where the rounding error started showing up
Hi Jim, unfortunately I got stuck here at home as the big snow storm made its way up here along Lake Superior. Travel through northern Minnesota and Wisconsin was just too risky. I hope you have a great time there, and I'll probably see you at VCFMW!
I know this is a couple years old, but thought I'd answer in case you're still interested. The answer is - partly, but that's not the biggest issue. Using Robin's example where he adds 0.01 to his variable in each loop iteration: 0.01 represents the value of 1/100. Now this is a number that can be represented exactly in decimal, but cannot be represented exactly in binary, because 1/100 cannot be represented as a sum of powers of two. Consequently, the BASIC interpreter cannot add EXACTLY 0.01 to anything, so it has to add the closest approximation it can, which turns out to be - in binary - 0.000000101000111101011100001010001111010111, which in decimal translates to approximately 0.00999999999999091. So right off the bat, there is a rounding issue occurring. However, this is not the only issue. Even if Robin had chosen a number that CAN be exactly represented in binary (e.g. 0.125), floating point rounding errors will always accumulate over time. Why? Because the C64 (or any computer for that matter) cannot represent an infinite number decimal places. In fact, floating point representations don't really represent a specific number of decimal places at all. Rather, they represent a fixed number of significant digits (or in binary a fixed number of significant bits). Any calculation that increases the number of significant bits in the result, will ultimately lose the least significant bits of the result. This is referred to a loss of precision, and it affects all floating point representations everywhere. For a concrete example, a C64 floating point variable has 32 bits of precision. With this precision, it can exactly represent all integers from 0 through 4,294,967,296. It can also exactly represent integers MUCH higher than this, but not all of them, and as the numbers get higher, there become more gaps between the integers that can be represented. Like I said, 4,294,967,296 can be represented. And so can 4,294,967,298 can be represented. But 4,294,967,297, which is right between them, cannot! Similarly, 2,199,023,255,552 can be exactly represented. But the NEXT integer that can be exactly represented is 2,199,023,256,576. There are 1023 integers in between these two numbers that simply cannot be contained in a BASIC floating point variable! This is because they require more than 32 significant bits of precision to represent. They can only be rounded to the closest number that CAN be represented. In the grand scheme of things, repeated mathematical operations on floating point numbers are what cause rounding errors (since loss of precision tends to accumulate over time), rather than conversions between decimal and binary, which typically only happen at the beginning and end of the process. Incidentally, the results printed on screen by BASIC do in fact suffer a loss of precision when converting back to decimal, since the numeric printing routine artificially limits the printed results to 9 significant decimal digits, even if more are available, but these errors do not accumulate with each loop iteration, since the internal binary representation of the number does not change.
Favorite one?? It's so hard to choose, but I'm gonna go with ?0+""+-0 causing the system to hang. That's just so unexpected. My VICE emulator just says "Main CPU: JAM at $0008" in the status area. Disassembling at $0008 just shows a JAM op code.
If you open monitor after the CPU jams and use the "cpuhistory" command in the monitor, you'll see that RTS instruction caused the jump to zero page. The RTS instruction returns from subroutine by fetching 2 bytes from the stack and jumping to the next byte from the fetched address in order to continue execution. You can set VICE to open the monitor whenever CPU jams.
It's nearly 100%. It's possible to make a C64 program that won't work on the C128 in 64 mode, but you'd pretty much have to be doing it on purpose, exploiting the few differences deliberately.
Almost all C64 games work on the C128's C64 mode, except those that purposely or accidentally write the wrong values to the couple extra registers in the video chip. I don't know for sure how many, but I think we're talking about a few games out of thousands, and even those ones have likely been patched so they work. There are more cartridges that don't work due to slight differences in timing, but it's again a small number. Generally, I use my C128s in C64 mode frequently and never have any trouble.
You should make an episode on the "B.Y. TIM" marking on the 3rd revision of the SID (6581R3). As of today, only the "B.Y." mystery has been "solved" (Bob Yannes); the "TIM" is the real mystery now.
Unfortunately, I don't have anything to add beyond the B.Y. = Bob Yannes suggestion. Although I suppose I could get more people thinking about the "TIM" part if I mention it in a video.
Remember the P90 and their Floating Point math problem. There was a joke, "why did Intel call the 586 Pentium"? Because when they added 100 to 486 they got 585.99999999999999999. ;)
Typing 350720 into cbmHandBasic, the iOS basic “emulator” crashes the emulated machine, sometimes causing a crash loop. Looks to be authentic commodore basic, alright. I wonder if it’s running the real KERNAL as well.
There is another one that causes a lockup on early C64s. I remember something about on switch on moving the cursor up and pressing return. Anybody know it?
Yes, my first C64 had that bug. I can't remember entirely how to cause it, but it involved typing a long line of BASIC at the bottom of the screen, which cause the screen to scroll up, then hitting delete right after. The computer would freeze up, telling you to press play on the cassette drive, and the only way out was to have a datasette hooked up, hit play, and then you could stop it and continue using the computer. Otherwise your BASIC program was lost - very frustrating!
4:16 - That command is trying to execute code at location $0003, then encounters an opcode of $22 at location $0008, which locks up the computer. Not sure how the program counter gets to that location in the first place. Any thoughts?
Right before the crash happens, there's RTS instruction, which tells the CPU to jump to address being one byte ahead from one being stored in stack at the stack pointer. At that point, the stack pointer points to location in stack, where there are 2 consecutive $00 bytes. This causes the CPU to jump to address $0001. The CPU begins executing the data in zero page as code, however it quickly encounters the roadblock as it tries to execute instruction $22, which causes the CPU to halt. You can make the VICE emulator to display the monitor when the CPU crashes. With "cpuhistory" command you'll get a list of opcodes, which got executed up to that point. If you set the execution breakpoint at the RTS instruction, right before the address $0001 gets executed and recreate the bug again and disassemble the stack(region $0100 to $01ff) after the breakpoint is hit, you'll be able to locate the exact pair of bytes in the stack located at the stack pointer, which was treated as return address.
Yes, you have to do a Stop+Restore before the POKE 781,96: SYS 58251. I think that clears the A and Y registers properly to trigger the effect. I haven't looked into it fully though.
Hi! I was testing the various bugs on my c64c when this happened: with the command 10? "" + - 0, the cursor disappears and the function keys like "Shift + RunStop" do not even work, does anyone know what it is??
Apparently C64 floats are similar to IEEE 754 but have some important differences explained here: www.c64-wiki.com/wiki/Floating_point_arithmetic#Comparison_with_IEEE_754_single_precision
Being "raised" in TI-99 world but been having gained a taking to the C64 in the last few years, the one thing I think the TI does better is the whole floating point thing. I was rather surprised how sloppy they are in C64 BASIC. My conclusion: TI BASIC is superior for math-related work while C64 BASIC is superior for, well...... just about everything else 😂
-I let the following one-liner run for about 5 minutes (bear in mind how slow TI BASIC is when you see the result).... > A=0 10 A=A+0.01 :: GOTO 10 >PRINT A 279.99 So, even going up to almost 300 and it still hasn't gone off. I suspect I could let it run even longer and still not get any rounding error (yet).
If the joystick is in port #1, then the printing will slow. That's because the joystick and keyboard share the same port on the CIA chip; it reads both. Pushing the joystick left uses the same pin as pressing CTRL on the keyboard, which deliberately slows down printing. To avoid that, use a joystick in port #2.
@@8_Bit If point joystick 1 to left makes the same character as the control key, can we poke a number into an address to turn off the control key character?
@@WagonLoads I'm not aware of any simple POKE that can fix it. One would probably have to copy the KERNAL ROMs to the RAM underneath and then patch out the CTRL key section. Possible, but it'd take some work.
I had that happen to me too :) Maybe we could blame the C64 - sometimes. And actually, the earlier C64s made from 1982 to early 1984 had even more bugs in them. I need to make a video about that sometime too.
I had a problem and thought I'd solve it with floating point numbers. Now I have 1.999999999 problems.
Ah, classic!
For a topical variant from back when I was in high school:
Q: How many Pentium designers does it take to screw in a lightbulb?
A: Hmm... I ran a simulation and got 0.9999997 Pentium designers...
...but a bit ain't 1
@@Roxor128 This is why this CPU is called Pentium and not 586. They tried to add 100 to 486 using it.
What's interesting is just how much I never knew about my c64. I'm learning more now 30 years after having one than I ever knew back then. :/
Get you another one. I found one on Ebay for like $100 and got an svideo connector to hook up to a “good enough” 720P flat screen and it looks pretty darn good. Cheap 1541s and 1571s out there too. BC quest for tires is still a blast and these experiments the author posts are fun to try.
For the record I know the svideo isn’t pushing a 720P signal but the C64 output on the display is still awesome.
Tell me about it....if information like this was so readily available back then I would've been So much further ahead.
Agreed drop dead. I now have 3 new C64s...a redone NTSC to Pal conversion machine, a C64 Reloaded MKII machine and an Ultimate 64 in a new C64C case. Doing some programming again as its been decades doing anything in 8 bit and the raw power and control you have is really liberating.
Fascinating, I owned the original c64 when it first came out in the UK, I was a teenager then. Lol I’m over 50 now. I wish I had kept it as I would love to have tried these quirks out. Also I really enjoyed poking things into the screen. I was never a programmer but I was amazed at the graphics and music people got out of the computer back in the day. Looking back the SID chip was my favourite audio chip. Your videos have brought back great memories, I thank you for that. Keep up the great and interesting work.
Update: The storm going through Minnesota and Wisconsin may prevent me from reaching the Midwest Gaming Classic this weekend! So... have fun without me, maybe!
ERRATA: I (and the C64) made a mistake in the 9^X example at the end: by 9^9 the rounding error has increased to a whole number, so the number displayed is one greater than it should be! Thanks to the commenters who pointed this out.
And here's this episode's index:
0:00 Intro / Midwest Gaming Classic
1:44 REM Shift-L bug
2:38 ?””+-0 crash
3:46 ?0+””+-0 hard crash
4:31 Hit Stop+Restore keys, then: POKE 781,96 : SYS58251 “screen saver”
5:40 M FFF6 Robert Russell / Bob Yannes
7:11 350720 crash
8:36 A=A+0.01 float rounding error
11:07 9^X exponent float rounding error
Watching this from the upper michigan area and its horrible here. Storm is kickin good. White out. Great episode by the way. My fav bug is the adding bug. Wow! Thats a common thing to do add by hundredths.
Some more floating-point weirdness: try to print the value 946.352946. Just PRINT 946.352946. The result won't be what you would expect. And that number wasn't even specially constructed to cause this effect, it's the exact number of milliliters in a (U.S. liquid) quart.
There was a pretty long post about the BASIC floating point math on comp.sys.cbm(?) back in the day. For those interested it is preserved in issue #12 of the famous C= Hacking magazine.
9^9 is actually 387420489. The error has accumulated to a whole number.
But my C64 says it's 387420490 - you're saying it's wrong? :) Thanks Jim, I should have checked that.
:) The floating-point format the C64 uses is capable of representing 9^9 exactly, so it must be rounding errors in the exponentiation routine itself. Interesting, but not really surprising. Floating point is an invention of the devil. ):->
indeed... the c64 is a full number off ...
it's also on par with the deviation that is building up on the other powers of 9.. as you can see for yourself the number is always getting bigger, so at a certain time it just has to cross the comma... my guess is that once u use any power higher than 9th it's always more than a whole 1 deviation (probably 1, 10, 100, ... with 9th, 10th, 11th power) I don't have a c64 anymore so i can't check by myself
This type of error can be found on just about any high-level computer language on any type of computer especially those written by Microsoft. It still happens today even in Visual C++. It doesn't seem to occur if you choose to implement BCD math routines however. I had many an argument with Mr. Gates about his math routines back in the day. I remember one instance where a customer of the place I worked for in the '80's came in complaining that there was something wrong with the computer because he balanced his checkbook and the computer was a penny off. All I could tell him is buy better software.
Even A%=9:?A%^A% gives this error. Weird.
THANK YOU for putting up effort in all these C64 Videos!! The C64 is often considered an old and simplistic homecomputer, but it aint. it contains all kind of wonderful engineering, tricks and wizardry that even by today standards amaze me. I bet the C64 will still live on even when we are all gone.
It's amazing how much there is to study and learn about it, and it still fascinates me after all these years. Thanks for watching!
Hi Robin! Tremendous work! Thanks for taking the time to share these experiments and tips. I have thoroughly enjoyed each video, and have a new appreciation for my childhood computer of choice! I have a "thec64 mini" now, but hope to pick up a real c64 soon. My 3 older kiddos have been tinkering in C64 BASIC, and I'd love to put a real breadbin or c64C in front of them.
That's great, I've had some of my kids do a bit of C64 BASIC programming too. The full-size THEC64 is getting closer to completion so that might be an option too. It apparently will boot directly to BASIC!
Bugs in the BASIC interpreter! I'm surprised there aren't more. I've spent most of my programming career working with packed and zoned decimal numbers, so floating point has always fascinated me.
Fortran got around that by forcing floating points to have well-defined characteristics like the number of significant decimal places
2:39 I use "?" as an alias for a command-line calculator program on my Linux desktop, since I got used to having that power on the Commodores.
4:27 When a VIC-20 was my only computer, I made a tool out of a paperclip to short two specific pins of the User Port together to do a hardware reset.
5:07 Is there an actual pattern to the question marks?
10:04 The unexpected thing is that BASIC doesn't have GREATER problems with floating-point round-off.
10:57 Even a value like the "1.23" that displays correctly might not be quite right internally, so you can't even count on the equality of values that look the same. BASIC stores LOG10(2^32) = 9.63 decimal digits of precision into floating-point variables but only displays 9 digits. However, you can always count on the equality of integer values where all intermediate values were intergers. E.g., A=A+1 will always be exactly an integer if A starts as an integer (unless it overflows ±2^32-1). www.c64-wiki.com/wiki/Floating_point_arithmetic
11:19 Exponentation, even to the power of an integer, is calculated using the mathematical identity b^x = EXP(x*LOG(b)). It doesn't use open loops (e.g., executing 1.001^10000 as 1.001 times itself 10000 times). The EXP/LOG method takes a constant amount of time using series expansions that involve multiplications, additions, and fractional constants that can introduce floating-point round-off errors. www.c64-wiki.com/wiki/EXP
12:27 The 9^9 case didn't correct itself - it's off by a full integer! On a calculator with more precision, 9^9 = 387420489.
Re: paper clip trick. Ha I totally remember that. I used to do that while playing games. Then I ran a program that I wrote which would iterate through all the possible locations for graphics memory. If you were lucky you could get a "screen shot" of your game that way. I even wrote it out to disk using run length encryption (which I thought I had invented but quite obviously didn't).
As for the floating point error, the exact moment it happens depends on the particular floating point format. Commodore BASIC uses 40-bit Microsoft Binary Format, while modern processors use 32-bit and 64-bit IEEE 754 formats. In particular, when adding 0.01 with 64-bit IEEE floats, you will get an error as soon as 0.060000000000000005. I think it depends on where you cut the binary expansion of 0.01: In 40-bit MBF the next two bits after the cut are 00, in 64-bit IEEE it's 10, so the error is more noticeable and accumulates sooner.
As for 10remL, I did some experiments and it seems like the graphics characters are turned into various BASIC tokens, with shift-L being probably the only one that causes the error. The formula between the PETSCII values and token numbers seems to be non-trivial and I'd love to see some more info about that.
The crash caused by adding string to numbers is also interesting. The behaviour is non-deterministic: the same expression can either do nothing, cause a break, cause a syntax error, or crash the machine completely. Also a very interesting topic to explore, it requires digging into BASIC's expression parser though and it might be complicated.
When BASIC tokenizes the REM statement, Shift-L is converted to $CC. BASIC tokens all fall in the range of $80 to $CB (except for pi, which is $FF).
Now you see why Shift-L causes the error. It's referencing a non-existent token, and the interpreter bails with a SYNTAX ERROR. (I have no idea why Shift-N thru Shift-Z don't cause the same error.)
@@SpearM3064 I noticed that shift-K turns into GO, which is $CB, but shift-M turns into $81, which is FOR. No idea why it skips $80 It then follows the sequence until shift-minus ($7D) which turns into ON ($91), and the next PETSCII character is π. I haven't analysed exactly which tokens are generated after that, the pattern seems a bit more random though.
@@vytah Interesting. To be honest, I had a Commodore 64 for about a decade (and in fact, I still have two of them, plus a 1541 and a 1541-II, in my closet); I don't know why I never analyzed this myself in all that time. Thanks for doing the research!
Hey there! I groggily clicked on your video this morning mistaking it for one by another c64 and BASIC enthusiast whose name begins with "8-Bit".
And I'm really glad I did! Subscribed and will be hanging around for a while. Keep up the great work! Cheers.
I'm glad you clicked on it too :) Thanks for subscribing.
I've actually been on that other guy's show a few times, most recently in his "dream computer" episode in a couple short segments.
You are the Bob Ross of Commodore adventures. I mean that in a very supportive way. Thanks so much for bringing back the memories of my teen years. Your videos are very intriguing!
Haha, I never thought of it like that, but you're absolutely right. I can watch Robin's videos all day long and never get tired of them. I used to watch Bob Ross for hours as a kid the same way. Just something "good" about the whole process. Can't explain it, but it works!
a tip i always give about math with floating point numbers is to either use numbers like 1 / (2^n) (because those numbers fit perfectly into floating point numbers and are completely immune to Floating point errors). or avoid decimal points unless printed out
so instead of:
0 PRINT X : X = X + 0.1 : GOTO
you would do:
0 PRINT X / 10 : X = X + 1 : GOTO
the more digits after the decimal point you want, the more you digits you have to add onto the 1 to divide by.
so 1 digit after the comma you have to divide by 1 with one 0 after it. so 10. 3 digits (0.125 for example) would need to be divided by 1000, and so on.
Proxy do you maybe mean numbers like 1/(2^n) instead? As is, it seems like you're saying 1/9 will fit perfectly into a binary representation but that's certainly not the case. Cheers!
@@Sharklops oh i'm sorry that's a typo.
yes i mean what you said. it just has to be
1 / (some power of 2)
Thanks for the shout out to my VR64 project! Another great video Robin!!
Any time Jim. We should work together on a video in the near future :)
Very interesting. Those rounding errors probably explain why the INT() statement is so commonly encountered in Basic programs.
Hi Robin it's always a pleasure to watch your videos. I have found another FP bug, longtime ago.. try to print the sin(pi) and you have not 0 but a fp number : 3.whatever times 10 powered to -9 . Another rounding error. There are many.. !
sin(pi) = 0 only in radians and I bet the default angle system on the C64 is sexagesimal degrees not radians
No, C64 expects radiants as argument. Try printing COS(180) and you won't have -1. try with cos(pi) and you have it.
Besides the SID component, Bob Yannes also designed the vic20 and c64 systems.
Interesting. I had heard he had helped prototype the VIC-20 but didn't know anything beyond that.
In your very first example with the REM shift L, I seem to remember some basic programmers using this as a sort of rudimentary copy protection way to keep people from looking at their code. Of course if you knew the LIST and line number plus one you could get by it but I also remember some folks loading lines of code with this sequence at the beginning so it would take a while to find the line you could list from. Thanks for sharing!
Yes, I remember seeing this when I was a kid and being bewildered by this. There are other REM tricks similar to this, I'll probably make a whole video about it unless someone else makes a good one about it first :)
@@8_Bit One trick I used involved a memory editor. I would create a REM statement with about six blank spaces and a Shift-L. Then I would go in with the monitor on my FastLoad cartridge and replace the spaces with $14 (DEL) characters. So when you LISTed the program, all you'd see was the SYNTAX ERROR. If you were paying attention, you might be able to see the line number and REM statement for a fraction of a second before it was deleted. The idea was that it would be harder to figure out what the "line number plus one" was. For the most part, I never bothered "protecting" my programs that way, though.
Re-watching this video years later... and I just ran that A+0.01 program on my C64. If you let it go for a while, it gets stranger and stranger. Sometimes the rounding error increases over time, other times it decreases, and every now and then it starts printing correct values again. By the time you get to what should be about 55.55, it's actually so far off it shows 55.55001, which is a pretty substantial error.
I think the floating point problem could be a good case for using integer variables if you need to do calculations and then compare. I can't recall if t he C64 had a function to limit the number of decimal places or if you had to use your own math to round it up properly? I do recall that trick with the REM and some other one I forget now, being used in some commercial BASIC games (I seem to recall Strip Poker used some trick like that) to prevent you from listing the program. Throw one of those between each line and you have a headache listing. I forget what they actually used.
My favourite by far was the trick where you relocated where the PRINT command prints to so you could PRINT out sprites, or sound effects etc... no reading and poking of data. It acted like a large, multipoke, where you set a range of memory. What you print being the characters that represent the values you want. It is an amazingly powerful trick to use. It even reduces the size of your program as you don't need all those data statements and a FOR->NEXT loop etc.
POKE209,0:POKE210,212:POKE211,0:?"@@@@@@@@@@@@@@@@@@@@@@@@@";
The @ is zero on the C64, so this particular print clears out the first 25 memory locations for the SID chip, effectively clearing it in one go. You poke the low byte into 209, the high byte into 210, so this prints zeros starting at 54272 + the next 24 memory locations. So just figure out the high byte/low byte, poke them into 209 and 210, then print there. I forget the memory location for sprites and what each sound location does, but look up the SID memory, 54272, what it does, change it and the following locations in this print string and make a sound effect!
I forget the exact numbers, but you can change those pokes to point to memory for SPRITES and use the same trick, each character is the number you wish to poke in that memory and you can create a sprint with one print. Amazing trick I loved back in the day, at least until I started to program in 6510 assembly anyhow.
Yeah, to round off you basically have to do some multiplication and use the INT() function to truncate. No built-in easy function for it.
I was just reminded of that PRINT to POKE trick, you use location 648 to change where BASIC thinks screen memory is. Somebody left a comment with a use of it to do that speaker click trick at 900+ Hz, way faster than the fastest we had achieved with the POKE methods.
To manually overcome decimal rounding errors you multiply the number you are working with by something like 100 or 1000 or 10000 (depends on the precision you want), do the math, the rounding error, if it occurs, always happens to the least significant number, make it an integer to drop any remaining decimal then back into floating point, and divide it by 100 or 1000 or 10000 (what ever you used to multiply). Dividing by 10, 100, 1000, etc, simply moves the decimal position and has no rounding error. This method also prevents the accumulation of errors.
C-64 has no PRINT USING "00.00" command or X = Float Using "00.00" format, but in some languages these only mask the rounding error and can accumulate, unseen, over repeated operations.
If you want to do calculations then compare with floats, the usual approach is to test if it's within some small value of the target, rather than equal to it.
A replacement for "if (x==0)" (supplied in C, given I've forgotten BASIC syntax):
#define epsilon 1e-6
/* do your calculations here */
if (abs(x) < epsilon)
{ /* do stuff for when x==0 */ }
If you want to test against a non-zero value, you could subtract x from it first using abs(val-x) instead.
I've never learned so much from floating hands. Keep it up!
absolutely love these kind of videos. Please keep em coming and please don't use any kind of music or whatever in the background, the silence just helps me getting absorbed into the subject matter and the nostalgia of those days
How many things I didn't know !! Keep it up, it's a lot of fun to discover new things!
Ah the good ol floating point error. Exactly the reason why i tend to use the 'int per decimal' method instead of floats.
great video. I will be creating a video on my channel to run some of these math oddities on the Atari 130XE Basic to see how it handles them ( or mishandles )
Cool, I subscribed, I'm looking forward to the video!
Back when I was programming dBase III+ to output to laser printer, I'd get odd offsets due to rounding errors The way I found to correct it on the fly with minimal interpreter overhead was to cast the result to string, then back to number so the value would look like VAL(STR()) BASIC 2 it would be VAL(STR$()) . I imagine that that sort of nested function would be pretty slow, based on what you've shown previously.
Edited for some blind stab at an 'English as a first language' vibe. :D
Oddly, the biggest culprit was something like 125/5 (from memory - the notes are in an R-Kive box in the attic, possibly labelled "1989 - Programming") that gave 24.99999999999999999... to whatever the precision was in dBase. I remember the Ashton-Tate support guy saying 'That's not possib... bloody hell...' so it wasn't 8088 IBM clone specific.
i liked the REM L bug because it uses one of the most basic, user friendly commands. And it was very interesting to see the float errors.
As always super interesting. Thank you and greetings from Germany!
Awesome curios hidden in the 64! Thanks for exploring them and putting this together.
Milwaukee? If you have trouble with your old Computers, I know some guys doing lightning fast VCR repairs there... *cough*
The results you got from poke 781,96:Sys58251 triggered a very old and rather vague memory from way back in the early '80s when I had my original C-64. I had stumbled across a poke that caused the C-64 to go crazy, changing screen/border colours, sometimes showing corrupt characters on the screen and triggering a shower of either exclamation marks or question marks (I forgot which), rather like the example shown here. Eventually after a random amount of time it would stop, with the computer frozen. I would get a slightly different effect each time. Sadly I can't remember the poke, though I think the first digit of it was 7. I tried to poke around with my present C-64, but have been unable to find it again.
I've never heard of that one - certainly sounds interesting!
Billy Mitchell is the King of Mame.
For anyone interested in getting a little more info about floating point errors, this Computerphile video featuring Tom Scott does a really good job of laying everything out: th-cam.com/video/PZRI1IfStY0/w-d-xo.html
TI 99/4A didn't have the floating point problem. This was the only thing its basic had that was so much better than any other home computer. It had BCD coded floating point with 13 digits precision and 10^-99 to 10^99 range. It essentially had the math routines used in TI calculators. What a bad surprize it was when I switched to Apple II later on and I discovered how bad binary floats are in reality.
Because TI99 probably used more bytes for floating numbers. Standard is 4 bytes, and 8 bytes for double precision, there were also 48-bit implementations (6 bytes).
@@cbm80amiga yes, TI took 8 bytes (13 BCD nybbles mantissa, 2 BCD nybbles exponent, and 1 nybble for the signs of exponent and mantissa. remains 2 bits unused or used for internal stuff. TI never was very open with their code.
Applesoft used 5 bytes, 4 for the mantissa and 1 for the exponent, giving 31 bit for the 1-complement encoded mantissa and 8 bits 2-complement exponent.
@@cbm80amiga The impoortant thing was that they used BCD to encode the numbers, which avoided the rounding errors we see in this video when converting to a string representation. Pocket computers from Sharp and Casio also used a very similar BCD encoding of floating points and except for IBM big iron machines, these decimal formats have disappeared and it's really a pity as they had some real advantages over the usual binary floats.
floating point granularity is why you use >=
Never used a c64 before because it was just a tad before my time, however I grew up on qbasic which was essentially the same just with up to 640K of memory.
I was fortunate enough be be a part of an online community of qbasic/quickbasic/qb45 fans in the mid 90's where we challenged each other with programming contests and shared tutorials and new discoveries.
After a few years, maybe 5 or so, qbasic and variants was getting harder and harder to run on the newer operating systems so a group of the fans got together to write a new compiler that would run on any linux or windows os's but still keep the old syntax and add some new ones plus full api support etc.
It ended up being called FreeBasic www.freebasic.net/ and I still use it from time to time today.
After 4 years of learning C-64 BASIC, I was forced to move over to ABasic when the U.S. Navy began putting IBMs in all office work spaces in the late 80s. That eventually lead me to QBasic and also QDOS. I still have QBasic that only runs in DOS Box, but the compiled programs from QBasic can be run (usually) from a console window. About the only thing that doesn't work properly, if at all, are POKE commands. Windows Vista and above will not allow direct memory access, or it's a problem with QBasic using absolute addressing on a system that uses relative addressing (?) QDOS, by the way, was a DOS plugin that added about 100 commands to DOS that could be put into a fairly complex DOS shell. There were entire games written that ran within a DOS shell. I never found the time to write much other than menu and program launching shells for my computer illiterate wife, but was always amazed to see the capabilities of IBM DOS that 99% of users didn't know existed.
With the shift + l trick you can actually do a lot more than that.. you can execute screen commands too like the reverse heart to clear the screen and you can change the colours of the text...
I first learned about it in an old basic game called the secret of bastow Manor and then years later I read in a computes gazette about the shift trick showing how to change the text colour and I realised you could do a lot more with it including cursor movements and more
floating point rounding was the most interesting, thank you. Cheers!
10:33 "it takes a long time in modern computers"
Meanwhile python: 0.1+0.2 = 0.300000000004
Still found the input parser fascinating, how flexible basic is plus the kernal routines in less than 40K .... You can even move the cursor to any part of the screen and press enter to excecute again. Rounding issues are all around, probably more noticeable in the C64 because is a SW based floating point unit with not much room to spare. For a personal home micro, is stunning. Always enjoyed the C64 as a console, but never put its potential to good use.
Nice to get a face to go with the voice, Robin. I was beginning to wonder if you were Thing's long lost "brother". You know, the other disembodied hand from the Adams Family... since hands usually come in pairs 🤜🤛 - Only kidding 😁
I love finding videos about stuff I don't know. But as you can imagine, this gradually becomes harder and harder, or at least when it comes to the C64... But somehow you're able to just keep the interesting videos coming 👍
I wonder to what extend Commodore fixed these bugs in the C128's basic. I have also fairly recently stumpled upon the Basic 8 ROM and floppies, which I didn't know even existed. Seems to mainly be added support for doing graphics on the 80 columns display and probably works best with a RAM upgrade on the VDC, which I have.
I do love hearing about the C64, but I also think the C128 gets a bit neglected on the web. Or at least when it comes to programming. Maybe you could venture into that stuff, once you run out of material about the C64? - it would be great to hear about the C128 at your level of thoroughness.
Thanks Carsten! Sometimes my second hand makes an appearance :) And I have appeared in full corporeal form at the end of the "The Extra Spaces in Commodore 64 BASIC Errors" episode. It may not be a coincidence that's my most down-voted episode. Though maybe it's because I'm singing and playing ukulele: th-cam.com/video/ZU7XZleSCAc/w-d-xo.html
My list of episode ideas is creeping towards 200 items now, so I hope to keep making interesting videos for a long time! But yes, it'd be great to explore C128 mode more and I should get to that eventually. In the meantime, check out Nybbles and Bytes' channel for some C128 focus.
Basic 8 is very interesting; I read about it a lot back when it was released, but never did try it myself. I'll put it on the list of ideas, thanks :)
Ooh, I'm all over Nybbles and Bytes... Impatiently waiting for the next video like a 5 year old for Christmas.
Speaking of... I did actually watch that video and found it quite odd, that I have never really taken notice of those extra spaces. But I apparently didn't get all the way to the end of it. Getting older I seem to get more easily distracted and sometimes struggle to keep my focus, so that's not on you. Anyway, watching it again now, I didn't find your singing that bad. I mean the music industry often puts out songs these days which are extensively more horrible 😉
I have a lot of old retros, but not all of them Commodore. Got 3 C128's of which I have decided to keep 2 of as original as possible, or at least on the outside. One of them has now gotten a problem with the character ROM, which I haven't quite sorted out yet.
The third was a really sorry looking thing I rescued from eBay, advertised as being non-functional and for spare parts only. So I decided to allow myself to go completely nutz with modding that one. I have mended the broken, scratched and discolored cabinet and given it a crazy multi-layered "rogue-red" paintjob. Much like the ones people put on their cars, which changes color depending on the surrounding light. I have fixed its guts, so it now runs again and did a NTSC to PAL conversion on it in the process (I live in Europe). Added some switchable JiffyDOS ROMs and a Servant/Basic 8 ROM to the U36 Socket. Thinking about making an adaptor and putting an EPROM in twice the size, for maybe a GEOS128 ROM and something else. It also has gotten a DualSID mod now with a 6581r4 and a 8580r5... the dual-mono stereo-effect just sounds awesome.... check it out:
th-cam.com/video/-cEuCG1C-yg/w-d-xo.html
I really want to do a memory upgrade on it... say to 256 or 512 KB. But it is quite hard to find any easy to follow documentation on how to correctly go by adding memory to the system. Having to distill practical how-to instructions out of complicated in depth technical explanations and diagrams from a PDF on the screen, it just seems to collide really badly with my focus issue these days. The only videos I do manage to find on the subject are of people proudly showing off their spaghetti-nightmare-wiring with a shaky video feed off their smartphones... Anyway, I don't know, maybe you know of someone who has experience with that sort of thing.
If you would like to see the red Ferrari looking beast in action there is another link below. It also shows off the twin monitors I have build and modded for it. They used to be VGA-only, but I just swapped out their electronics with two V56 universal LCD TV controller boards.
Doing the paintjob on the C128 ended up being such a nightmare to get through, that I haven't yet fully recovered enough to do a black paintjob on the keycaps or even the frame for the dual monitors yet... But this former scruffy looking C128 really is getting quite spoiled, I think 🙂
th-cam.com/video/DS-xRFz3F4g/w-d-xo.html
Nice work, I subscribed and watched both videos. And some of my videos are very long, it's no surprise that not everybody hangs in to the end :)
@@8_Bit I my case it has become a real disability, brought on by decades of excessively over-stressing my cognitive abilities, before finally crashing. The lesson that stress is something you should take very seriously, I guess I had to learn that the hard way.
I used to have what I thought to be a dream job, working in a small company programming customized plugins for financial and bookkeeping applications. But it has become increasingly harder for small businesses in software development to survive over the last many years.
Unless I actively make a constant effort to remind myself that "this is what you are doing right now", then my attention just seems to drift and repeatedly flicker left or right, without me even noticing it. Doing something where I use my hands like wood-, metalwork or electronics, something where there is a real physical object in front of me, seems to make it easier to localize my focus.
But I can be working on one thing, then have to go to the toilet and completely forget about it, then start on another thing, get distracted in another way and start on a third thing… even with the first 2 just a few feet away… and before I know it my workspace and living room is completely cluttered with a lot of haft finished projects and tools spread out into all corners. That is indeed how I end up finally realizing that I’m doing it, because of some in the moment much needed tool that I just can’t seem to find. It feels a bit like living with an annoyingly careless and really messy flatmate, except this one I cannot just kick out.
Seeking peoples pity or sympathy is not really my thing, or I don’t believe so. It is just everybody seems so focussed on maintaining their physical health these days and you really need to be as much aware of your mental health too or you might just end up losing something you always thought to be a defining characteristic of your personality.
I might also still be a bit traumatised by it all and kind of feel an urgent need to send out some message. But I have now also rediscovered my love for doing electronics and using my hands… and that is kind of a big deal and quite a positive thing too.
@@Zhixalom Sorry to hear that, but I'm glad you're finding some ways of coping that are positive. It's good you're mentioning it, as I've been noticing similar (but more mild) behaviours in myself, and what you've said helps bring it into focus for me. Thanks for the reminders.
Wow, these are really weird; thanks! The ones I'm most fascinated by are
where you can freeze the computer just by entering some too-big numbers
in direct mode!
I don't know if this counts as a c64 glitch, or just a basic weirdness.
But.
There's a small program on p53 of the c64 user manual, which when i modified it and fed it to BASIC on the schools rm nimbus pc. The entire network went haywire, tons of beeping, the dot matrix printers spewing random characters at high speed.
It caused our IT teacher to panic and cry.
This was not my intention, just a hilarious side effect.
Typed it out had run command ready, switched off monitor, hit rtn just as we were leaving the classroom.
All i did was to replace the + in line 20 with a * (this was what caused the network seizure)
and changed the 1 at the end of that line with an 8. (I don't know if this had any bearing on the outcome)
if anyone has an rm pc from 89/90 you can try. Though any machine running basic could perform this meltdown.
I never tried this on the 64 itself however.
==================================
"Wise man say, C, Very important
Without it we have only
BASI
OBAL
And PASAL"
long is not really wrong in the context of computer numbers because in the case of integers the std (short) signed int ranges from -32768 to 32767, unsigned goes from 0 to 65535 and then you have long integers-2,147,483,648 to 2,147,483,647 (obviously in 32 bit computers)
I think that's why I said it in the first place while recording and then while editing started having my doubts :) Thanks!
As a programmer I've had to deal with the fun of floating point library rounding errors many times. Any idea if these rounding errors are consistent across the various versions of Commodore BASIC or is it more a factor of the 8/16-bit arithmetic used by the processor? Luckily as a kid I didn't do any floating point math (that I recall) on my VIC-20 :-)
It's a factor of the exponent/mantissa format used by their version of BASIC. Two bytes (16 bits) for the exponent, five bytes (40 bits) for the mantissa. The entire Commodore 8-bit line and the Apple II line (running Applesoft BASIC) have the same rounding errors, because their version of BASIC derives from the same Microsoft core.
The Atari 400/800 does NOT have the same rounding error, because ALL numbers (integer or floating point) are represented in BCD (Binary Coded Decimal). On the negative side, this means that longer numbers take more memory. On the plus side, no rounding errors!
@@SpearM3064: Commodore BASIC floats have an 8-bit exponent and a 32-bit mantissa. Atari BASIC would still have rounding errors, just not decimal rounding errors. What is 1/3*3? If you have exactly 10 decimal digits, 1/3 = 0.3333333333 and 1/3*3 = 0.9999999999.
@@csbruce Well, yeah, Atari BASIC had to draw the line somewhere. If you have a repeating number like 0.33333, you don't want to fill your entire memory space trying to represent the number. I don't have enough experience with Atari BASIC to know how many significant digits it kept.
@@SpearM3064: Even if you filled the entire memory with 0.33333…, the stored value would still be slightly off. According to a broken web page I found, Atari uses six bytes to represent a float, including one byte for the exponent and sign in binary and five bytes for the 10-BCD-digit mantissa. It has an odd normalization practice where it only insures that the most-significant BYTE of the mantissa is non-zero, I guess to avoid bit-shifting the BCD digits between bytes. Of course, this will introduce extra "wobble" into its true precision.
www.retrocomputing.net/parts/atari/800/docs/atari_os/atari_os_user_manual_08.htm
@@csbruce One of the programmers who helped write Atari BASIC and Atari DOS used to write for COMPUTE! magazine. If I knew how to get in touch with him, there are so many questions I'd love to ask him. Not because I want to learn more about Atari BASIC, but because I'm curious about the reasoning behind some of the decisions they made. The normalization practice is not the only odd thing Atari BASIC does...
Microsoft fuzzy floating point numbers:
The following square root calculations give skewed results.
? sqr(25)-5
1.86264515e-09
? sqr(9)-3
9.31322575e-10
This is apparently a problem that many Microsoft BASIC implementations had. There are other examples.
Thank you 8-Bit Show And Tell, for this. BASIC of the C64 looks fun and useful.
No one has answered the 'REM bug" in a year so I thought I'd look into it. This is not an explanation of the BASIC interpreter's listing routine but a hint as to what's triggering the unusual behavior.
First; in a BASIC line if any character is within quotes and not reversed, it is taken as a literal character to be printed to the screen. Reversed characters inside quotes are printing (escape) commands.
B; any shifted character that is NOT within quotes gets "tokenized" by adding 128 to it's petskii character number.
Next; [shift] L gets tokenized to $204; "L" = petskii (76) + 128 = 204
Lastly; $204 is the BASIC token for "Syntax Error" (ref: Computes Programming the Commodore - The Definitive Guide; pp 143, table 6-1; Internal Storage of BASIC Bytes) Strange that this has a token since "Syntax Error" is not a BASIC command you can use in a program.
Most Lastly; The reason attempting to list the token for "Syntax Error" actually triggers an immediate mode Syntax Error remains to be investigated.
"Kernal" makes me wonder whether there are also operating systems that have a "colonel".
I remember one that had a BOSS operating system.
the floating point precision is still a issue today. They are still not perfect and can cause bugs if you dosent counter checks it.
Yup, it's not a hardware limitation or anything -- you can see it just by evaluating an expression like "0.1 + 1 - 1" in Python. It's part of the price paid for the floating point representations we use. Some languages like Haskell include rational arithmetic (i.e. fractions) which don't suffer from this.
Hi Robin, I'm watching this in July 2019 months after the Wisconsin convention (hey, that's the beauty of TH-cam) but you say in the intro you were heading down from Canada. With Canada being the second largest country in the world, where in Canada? If it's a privacy issue, no problem. I've just subscribed and started binge watching some of your C64 and 6502 videos, great work! I'm going to hazard a guess based on accent... Sault St Marie? Regardless, keep up the great content! Your channel is a retro-blast and despite thinking I've mastered 6502 asm and the C64 world, I've learned some great little tricks so far! I was happy to see that these quirks "work" on Vice C4 Emulator (except the "screen saver" one) as well as my C64!
Good guess! I'm in Thunder Bay, "just" 8 hours west of Sault Ste. Marie. I'm pretty sure I mentioned it in one episode back in January or February when we were starting the Thunder Bay Retro Computer Club. Thanks for watching and commenting :)
My favorite one is the 9^A. Very interesting.
Is it possible that it's the print routine that's inserting the rounding error in the power example?
It seems to be a problem with the exponent operator itself. In the new episode I just released, (called "Commodore PC 50-II") I use a loop with multiplication and it comes up with the correct answer without any rounding errors.
Interestingly, those two Commodore BASIC bugs (PRINT ""+-0 and PRINT 0+""+-0) also crash Applesoft BASIC, which isn't too surprising given they are both based on the same Microsoft code. In the case of Applesoft, those two statements cause a bomb into the monitor (meaning a BRK instruction was executed, as theorized in the video). The first statement caused a break at $F4 (zero page) initially, which is rather weird. When I returned to BASIC from the monitor and typed the same statement, it caused a break at $208, which is inside the input buffer itself where the line typed is stored. So somehow the BASIC interpreter is jumping to addresses very low in memory. So perhaps either the stack or the CHRGET subroutine in zero page is getting corrupted, or perhaps the interpreter is looking up an address in a table and the index is too high, or something along those lines. It would be interesting to actually do a trace of the code in an emulator to see what is actually going on.
We had one with ;;;;;;; if I recall, you could write a very short print program with goto. Not sure the exact program now but the result was a screen of flashing strobe colors.
When you were doing that Luke incrementing incrementing the floating Point by 01, did you ever end up seeing a pattern in where the rounding error started showing up
See you Saturday!
Hi Jim, unfortunately I got stuck here at home as the big snow storm made its way up here along Lake Superior. Travel through northern Minnesota and Wisconsin was just too risky. I hope you have a great time there, and I'll probably see you at VCFMW!
@@8_Bit Someone should write a 6502 program to control the weather! See you this summer!
are floating point errors a result of converting from decimal to binary and back?
I know this is a couple years old, but thought I'd answer in case you're still interested. The answer is - partly, but that's not the biggest issue. Using Robin's example where he adds 0.01 to his variable in each loop iteration: 0.01 represents the value of 1/100. Now this is a number that can be represented exactly in decimal, but cannot be represented exactly in binary, because 1/100 cannot be represented as a sum of powers of two. Consequently, the BASIC interpreter cannot add EXACTLY 0.01 to anything, so it has to add the closest approximation it can, which turns out to be - in binary - 0.000000101000111101011100001010001111010111, which in decimal translates to approximately 0.00999999999999091. So right off the bat, there is a rounding issue occurring.
However, this is not the only issue. Even if Robin had chosen a number that CAN be exactly represented in binary (e.g. 0.125), floating point rounding errors will always accumulate over time. Why? Because the C64 (or any computer for that matter) cannot represent an infinite number decimal places. In fact, floating point representations don't really represent a specific number of decimal places at all. Rather, they represent a fixed number of significant digits (or in binary a fixed number of significant bits). Any calculation that increases the number of significant bits in the result, will ultimately lose the least significant bits of the result. This is referred to a loss of precision, and it affects all floating point representations everywhere. For a concrete example, a C64 floating point variable has 32 bits of precision. With this precision, it can exactly represent all integers from 0 through 4,294,967,296. It can also exactly represent integers MUCH higher than this, but not all of them, and as the numbers get higher, there become more gaps between the integers that can be represented. Like I said, 4,294,967,296 can be represented. And so can 4,294,967,298 can be represented. But 4,294,967,297, which is right between them, cannot! Similarly, 2,199,023,255,552 can be exactly represented. But the NEXT integer that can be exactly represented is 2,199,023,256,576. There are 1023 integers in between these two numbers that simply cannot be contained in a BASIC floating point variable! This is because they require more than 32 significant bits of precision to represent. They can only be rounded to the closest number that CAN be represented.
In the grand scheme of things, repeated mathematical operations on floating point numbers are what cause rounding errors (since loss of precision tends to accumulate over time), rather than conversions between decimal and binary, which typically only happen at the beginning and end of the process. Incidentally, the results printed on screen by BASIC do in fact suffer a loss of precision when converting back to decimal, since the numeric printing routine artificially limits the printed results to 9 significant decimal digits, even if more are available, but these errors do not accumulate with each loop iteration, since the internal binary representation of the number does not change.
Where abouts in Canada are you? I'm in south eastern Ontario myself.
Up in Thunder Bay, northwestern Ontario :)
Favorite one?? It's so hard to choose, but I'm gonna go with ?0+""+-0 causing the system to hang. That's just so unexpected. My VICE emulator just says "Main CPU: JAM at $0008" in the status area. Disassembling at $0008 just shows a JAM op code.
If you open monitor after the CPU jams and use the "cpuhistory" command in the monitor, you'll see that RTS instruction caused the jump to zero page. The RTS instruction returns from subroutine by fetching 2 bytes from the stack and jumping to the next byte from the fetched address in order to continue execution. You can set VICE to open the monitor whenever CPU jams.
@@Titanic4 thanks. I didn't know that was an option.
Does BASIC 3.5 in the Plus/4 have the same bugs?
I believe some have been fixed but some remain but I don't know for sure. Would make an interesting video for the future :)
Love your vids. Thanks a lot "Teaching Hand" !!
Wow, never knew C64 BASIC could act just like JavaScript....
Like a fussy 2 years old boy.
In your opinion, how close is the C64 mode of the C128 to the actual C64?
It's nearly 100%. It's possible to make a C64 program that won't work on the C128 in 64 mode, but you'd pretty much have to be doing it on purpose, exploiting the few differences deliberately.
@@8_Bit Thanks for the quick reply. What about games, cartridges, etc.? Is there any C64 software that won't work in C64 mode on the C128?
Almost all C64 games work on the C128's C64 mode, except those that purposely or accidentally write the wrong values to the couple extra registers in the video chip. I don't know for sure how many, but I think we're talking about a few games out of thousands, and even those ones have likely been patched so they work. There are more cartridges that don't work due to slight differences in timing, but it's again a small number. Generally, I use my C128s in C64 mode frequently and never have any trouble.
Love these insights, keep em coming 😀
You worked with Jeri Ellsworth on the C64DTV?
Yes, it was a very fun project to be involved with, and it was great working with Jeri.
@@8_Bit that is freaking awesome :)
So much fun! Bug that looks like a screen saver! Thanks for the double==double hint. Will watch out for it in other languages.
There's entire books about that and how to best work around it in general.
there is no repo being created for this video unless requested.
You should make an episode on the "B.Y. TIM" marking on the 3rd revision of the SID (6581R3). As of today, only the "B.Y." mystery has been "solved" (Bob Yannes); the "TIM" is the real mystery now.
Unfortunately, I don't have anything to add beyond the B.Y. = Bob Yannes suggestion. Although I suppose I could get more people thinking about the "TIM" part if I mention it in a video.
I was looking into coming this year, but after the vacation I took i cant :( have fun!!!!!!
Turns out I didn't make it either due to the snow storm being so bad in Minnesota. :(
Remember the P90 and their Floating Point math problem. There was a joke, "why did Intel call the 586 Pentium"? Because when they added 100 to 486 they got 585.99999999999999999. ;)
That value of 9^9 didn't correct itself - it should be 387420489, not 387420490.
Exactly - BASIC just added this error which for 9^9 was 1
I think, at 7:09, after the "RRBY", the "C" is for "Commodore" and the following signs looks like a Petsci Smiley! '-'
Typing 350720 into cbmHandBasic, the iOS basic “emulator” crashes the emulated machine, sometimes causing a crash loop.
Looks to be authentic commodore basic, alright. I wonder if it’s running the real KERNAL as well.
Seems to not have the KERNAL:
list
10 FOR X = 65526 TO 65535
20 PRINT PEEK(X)
30 NEXT
READY.
run
0
0
0
0
0
0
0
0
0
0
READY.
Oh yeah, it handles lower case by default. Definitely not the commodore KERNAL
Have you tried entering PETSCII characters after a REM statement and then listing the program? And why it happens?
I had an Atari 400 and it had bugs but I didn't know the C64 basic was so buggy.
"Combine these together"? So... "put these together together"? Oops! :-D
There is another one that causes a lockup on early C64s. I remember something about on switch on moving the cursor up and pressing return. Anybody know it?
Yes, my first C64 had that bug. I can't remember entirely how to cause it, but it involved typing a long line of BASIC at the bottom of the screen, which cause the screen to scroll up, then hitting delete right after. The computer would freeze up, telling you to press play on the cassette drive, and the only way out was to have a datasette hooked up, hit play, and then you could stop it and continue using the computer. Otherwise your BASIC program was lost - very frustrating!
@@8_Bit That's an even stranger bug!
4:16 - That command is trying to execute code at location $0003, then encounters an opcode of $22 at location $0008, which locks up the computer. Not sure how the program counter gets to that location in the first place. Any thoughts?
Right before the crash happens, there's RTS instruction, which tells the CPU to jump to address being one byte ahead from one being stored in stack at the stack pointer. At that point, the stack pointer points to location in stack, where there are 2 consecutive $00 bytes. This causes the CPU to jump to address $0001. The CPU begins executing the data in zero page as code, however it quickly encounters the roadblock as it tries to execute instruction $22, which causes the CPU to halt.
You can make the VICE emulator to display the monitor when the CPU crashes. With "cpuhistory" command you'll get a list of opcodes, which got executed up to that point. If you set the execution breakpoint at the RTS instruction, right before the address $0001 gets executed and recreate the bug again and disassemble the stack(region $0100 to $01ff) after the breakpoint is hit, you'll be able to locate the exact pair of bytes in the stack located at the stack pointer, which was treated as return address.
Great video. Greetings from Poland!
Awesome, loved seeing this info!
What does ? 𝝿↑3.63307 result in?
I gave it a try. The answer is: 64.0000463
@@8_Bit Close to 64 at least 😉
@@El_Grincho At least we have the INT() function to fix that :)
The "screen saver" isn't working on my machine. I just get "? ERROR" and some white square characters
Me too if you type only SYS58251
Instead with POKE781,96: SYS58251 worked
Same here.It doesn´t work.
@@christianknechtel8683 Try like this:
after switching on the commodore, press run / stop and restore
then enter the two instructions.
Yes, you have to do a Stop+Restore before the POKE 781,96: SYS 58251. I think that clears the A and Y registers properly to trigger the effect. I haven't looked into it fully though.
@@8_Bit I just tried this:c000 lda#$00
tay
ldx#$60 (96)
jmp$e38b (58251)
Didn´t work.
Hi! I was testing the various bugs on my c64c when this happened: with the command 10? "" + - 0, the cursor disappears and the function keys like "Shift + RunStop" do not even work, does anyone know what it is??
The CPU has halted after trying to execute invalid instruction. The Kernal has to be running for the keyboard to give expected response.
can they not use the IEEE754 representation of Floating Point.
Apparently C64 floats are similar to IEEE 754 but have some important differences explained here: www.c64-wiki.com/wiki/Floating_point_arithmetic#Comparison_with_IEEE_754_single_precision
Exponentiation is just repeated repeated addition :P
Love this video. Nice work 😀👍
Being "raised" in TI-99 world but been having gained a taking to the C64 in the last few years, the one thing I think the TI does better is the whole floating point thing. I was rather surprised how sloppy they are in C64 BASIC. My conclusion: TI BASIC is superior for math-related work while C64 BASIC is superior for, well...... just about everything else 😂
-I let the following one-liner run for about 5 minutes (bear in mind how slow TI BASIC is when you see the result)....
> A=0
10 A=A+0.01 :: GOTO 10
>PRINT A
279.99
So, even going up to almost 300 and it still hasn't gone off. I suspect I could let it run even longer and still not get any rounding error (yet).
"10:00" - that's floating point numbers for you.
So, how is a random call into the KERNAL with no parameters set up considered a bug, an easter egg or even a "screen saver"?
Actually, the poke that is performed _is_ a parameter, it's just not a value that the routine expects.
Here is a bug
10 for x=1 to 1000000
20 print x
30 next x
While this is running, move the joystick to the left and see what happens.. Is there a fix?
If the joystick is in port #1, then the printing will slow. That's because the joystick and keyboard share the same port on the CIA chip; it reads both. Pushing the joystick left uses the same pin as pressing CTRL on the keyboard, which deliberately slows down printing. To avoid that, use a joystick in port #2.
@@8_Bit If point joystick 1 to left makes the same character as the control key, can we poke a number into an address to turn off the control key character?
@@WagonLoads I'm not aware of any simple POKE that can fix it. One would probably have to copy the KERNAL ROMs to the RAM underneath and then patch out the CTRL key section. Possible, but it'd take some work.
I really want to explore the Windows subsystem like this. There must be some quirks hidden like this as well that make you machine cra#ü3211§1#-
I spent a lot of time in my room as a kid wondering why I couldn't find the error in my programming. Now you tell me the C64 wasn't perfect? :D
I had that happen to me too :) Maybe we could blame the C64 - sometimes. And actually, the earlier C64s made from 1982 to early 1984 had even more bugs in them. I need to make a video about that sometime too.
@@8_Bit Would enjoy that if you did. I still feel the love for my C64 though, so I can't get mad at it.
Amazing
Nice quirks..heheh.
Great channel!
brilliant!
10 poke 775,1 20 poke 808,225 ( no listing and you can not break the program if it runs :) 30 ?"hello world" 40 goto 30
From back when you were allowed outside :-(