0.3 does not equal 0.3?!? Codea bug? Lua bug? Ambush bug?

@dave1707 yes, I understand, and it seems we’re talking at cross-purposes. You’re emphasizing the limits of expressing any kind of numerical value in a bit-constrained system. I’m addressing how those limits are conveyed or not conveyed to the user.

@UberGoober I guess it is hard to look up something when you don’t know that you have to.

I don’t think anyone should make excuses for the way floating point has historically been handled in programming languages. It is really weird and unexpected and it is “trade knowledge” and it is pretty crappy and constantly bites people in the ass. It would be better if all of this wasn’t true or there were warnings or other mechanisms to surface the situation to learners, but it is what it is at this moment in time.

Engineering is about making tradeoffs in the face of imperfect realities and the tradeoffs between storage size, performance, and precision is an especially difficult one. Decisions were made decades ago. Standards were written. Conventions established. It’s not an unchangeable situation, but the first step is knowing what you’re up against. :slight_smile:

tointeger()? .. ""? Tryed already?

I had never thought floating point numbers and their inexact representation in programming languages implementations was a “trade knowledge”. I think it is something you learned pretty early on, if you started with C, Pascal or even BASIC. And frankly, it only ever bite you in the ass once. After that one time you should know better. Perhaps today, when newer languages are further removed from hardware, it is less common that you would bump into accuracy of floating point numbers.

There are also an entire classs of numbers that you cannot represent accurately in binary or in decimal form even theoretically - irrational numbers. So, for comparing floating point numbers you would typically do something like:

local accuracy = 0.00001
if math.abs(a - b) < accuracy then
    print("close enough")
end

Tweaking the accuracy accordingly to your needs.

@UberGoober , i know you are arguing a broader point, and not asking for code snippets, but really i think @dave1707 is exactly right - some things you don’t know and then you learn, there is no conspiracy here :slight_smile:

@juce, may I kindly point out that you said you didn’t think it was trade knowledge and then went on to describe it as exactly that.

It’s Standard transmission vs Automatic, as it always is in these discussions. Just know what side you’re on!

@UberGoober, i see what you mean, and i guess you’re right to a certain extent… but then pretty much anything related to programming could be classified as “trade knowledge”. How would you define that term exactly?

@UberGoober Trade knowledge can refer to anything. I’m sure doctors know a lot of things about surgery that I don’t. You said above, That a group of people, who are already insiders, share a common understanding is, I think, what they call trade knowledge, and it's by definition the opposite of something plainly discoverable. I’m sure if I wanted to be a surgeon I would have to know a lot more than I do now. And even if I learned enough to be a surgeon, there would still be things that I wouldn’t know until I actually did surgery. The same applies to programming. There are things you won’t know until you start programming and actually run into them. You can’t expect to be told everything that you don’t know. Some thing you have to learn by doing it.

That’s really weird. Lua’s console does deceive you, in a way. Trying something similar in Python and JavaScript, I found that both perform the same arithmetic error, but they print out the inaccuracy to the console properly.
JavaScript console output:
Calculation is: 0.29999999999999993 Intended result is: 0.3 Calculation and intended result are equal: false
Maybe Lua should do something similar.

The print function in Codea rounds the result to 14 digits which would print .3 . By now everyone should know how floating point numbers are stored, how they print out, and that you won’t always get an equal comparison in some situations. That’s the way it works and it won’t change until Codea goes to 128 bit math which I doubt it ever will. To get a larger print result, use string.format which overrides the normal print function.

I walked into an art store once and I asked the counter guy “hey how long do these different paints last?”

He said “what?”

I said “These different kinds of paint, the brands and types, do you know how long it takes for them to lose their color or fade or distort or whatever?” These are paints for art, not for house painting, of course.

The guy says “I can’t do everything for you! It’s like you’re coming in here and asking me to make a painting for you!”

…which, you know, I wasn’t at all. I wasn’t doing anything of the kind.

But this was clearly an art school kid, frustrated with the dumb questions people come in off the street and ask, and my particular question–while not related to anything he was talking about–set off his “why should I have to do everything for you people” alarm. So I got the “why should I have to do everything for you people” reaction, even though my question regarded some very specialized knowledge that it wouldn’t be easy for just anyone to pick up on their own.

So, if you like, you can see my objection to the way floats are communicated to users as being in the “why should I have to do everything for you people” category. That’s a perspective you get to assert, and that’s what it seems like when you start to say things like “everything is trade knowledge”. Which is fine.

Parenthetically, when you say “By now everyone should know” I’m amused to speculate what you mean by the terms “by now” and “everyone”. Do you mean ever since all public broadcasting has been playing an hour of Codea tutorials every day since 2005? I agree! Those tutorials are really well done! People who don’t know Lua by now have only themselves to blame!

:wink:

Anyway, I personally don’t think this float thing falls under “why should I have to do everything for you people” category.

You do, I don’t, what are you gonna do? Peoples is peoples.

So when you write your book on coding in Codea, maybe you won’t take any special care to warn people about how Codea inaccurately represents floats in print statements (although does accurately represent them if you watch them as a parameter, btw). And when I write mine, maybe I’ll do a chapter on it. Yay, everybody’s happy, no big whoop.

@em2, see that makes sense to me. Of the two approaches, the Lua one and the Python one, the Python one is the one I would expect Swift to use, and I’m surprised it doesn’t.

@UberGoober When I said, By now everyone should know, I meant everyone reading this discussion. I still stick with my point that nobody knows everything and you’re going to run into things you don’t know. How you handle those situations are up to you. Are you going to say that someone should have told you about them before you ran into them, or are you going to say, that doesn’t work the way I expected and figure out why.

@UberGoober , i don’t think your example about art store counter guy is relevant. No one here was responding to you with that sort of attitude.

@juce I agree, no one had an irrational flip out in a cartoonish way. The attitude wasn’t the point.

Just so we’re all on the same page, the stuff we’re arguing about is what some people’s whole careers are based on trying to figure out. To make a language robust, accessible, powerful, parse-able, and feature-competitive is hard.

These questions constitute some people’s entire work life. We’re not going to resolve this is a you’re right, I’m wrong way. If it was that easy, we’d never be having the argument in the first place.

You’re right enough and I’m right enough that this could go on forever. Can we just say, hey, look, we’re in an argument that could go on forever, let’s not?

The guy who wrote the old Balance of Power game, wayyyyyyy back in the day, wrote a blog post called “Why Everyone Should Learn to Program,” a long long time ago. He called the first rule of programming “try to figure it out for yourself.” In other words, if you want to learn to program, before you ask anyone else how to solve a problem, see if you can do it on your own.

That’s what I think is true, and I think that’s what you guys are saying. I agree with that.

Oh and, @dave1707 , thanks for clarifying what you meant by By now everyone should know. I honestly didn’t know what you meant, it makes more sense now.

@UberGoober,

True. This lovely conversation could go on and on…
As so elegantly put by an XKCD comic here: https://xkcd.com/386/

Forgive me for another long post. And yes, it is not black and white, but I do feel that you’re more wrong than right. Let me make one last attempt to explain why. Then i will shut up. :slight_smile:

I completely agree with you about language design. It is hard, and it is also why there are so many programming languages around. Some are better designed and some are quite awful.

However, the choice of particular implementation of numbers is typically about hardware, not about language design. The way numbers are represented in computers is one of the most fundamental things in programming and in computers science and electrical engineering in general. If you were doing any sort of scientific calculations, solving equations with numerical methods, etc. - you would pretty much instantly learn about many various aspects of not just floating point numbers but integers too. But Codea is not about math, it has a different focus: it’s about graphical ideas and games. The brilliance of Codea is that people without any CS background or prior programming experience can start using it and be able to create something right away. And they don’t even need to think about numbers, bits and bytes.

However, in the end of the day, Codea is an application running on a computer, with a particular architecture. Lua is the programming language used by Codea, and like any other programming language it needs to handle numbers in a way that is memory-efficient and fast on a particular kind of hardware that it is running.

Just to give one example:

Let’s take integers, because there is nothing complicated about them, right? Wrong. You can fall into all sorts of traps. Integers can be represented with fixed number of bytes or with a varying number of bytes. They may or may not use highest bit as an indicator of negative value. A size of “int” may be defined by hardware or it may be defined by the language spec itself (as in Java). For instance, let’s say an “int” as a 4-byte integer, which represents both negative and positive values, and there is a specific combination of bits for the value of 0. This means that you can only represent values in this range: [-2147483648, 2147483647]. What happens when you calculation produces a value of 2.2billion? It depends. You may run in to an OverflowError or the value may simply be truncated. Neither is a good outcome, so in the situations where you do need to deal with big numbers, you may be able to switch to another fixed-width data type that uses more bytes (8-byte integer), or sometimes that is not possible, because the values are just too large. In that case, there are data types specifically designed for that: such as big integers in Python - bigger values use more bits, as needed. But, such specialized data types have their pros and cons - operations on them don’t map directly into hardware instructions, so math involving such numbers is slower.

Anyways, my point is that there are scenarios where neither floats nor integers can be viewed as simple black boxes that magically always work as you expect. Most often they do, but in some cases, you must take hardware into account.

Should that all be explained in detail in Codea documentation? Frankly, I don’t see the need. It’s not unique to Codea or Lua, so i think that it is totally reasonable to expect users to do some research to find out what’s going on, if/when they bump into “strange” behaviours.

@UberGoober , heh… took me too long to write my previous post!
You already added some good messages meanwhile, which kinda make my post unnecessary :slight_smile:

I am glad to have you guys sharing your knowledge here. Thank you.

So the thing that I’m not clear on is the thought process, the logic, behind these representations.

Let’s say I have two groups of people. I don’t know their exact numbers, but I know there are three families in each group.

Now, if I want to order Winnebagos for each group, and I can assume each family fits in a single Winnebago, I know that I can order 3 Winnebagos for one group and 3 Winnebagos for the other group. Each needs the same amount of Winnebagos.

However, if I want to order hats for each group, I actually have no idea how many hats to order, because I don’t know the size of each family. Not only am I unable to say how many hats one group needs, I am completely unable to say that they need the same amount of hats.

Right?

So let’s say Lua and I were discussing this situation.


Me: How many Winnebagos in group 1?

Lua: 3

Me: And how many Winnebagos in group 2?

Lua: 3

Me: Ok. So group 1 and group 2 have the same amount of Winnebagos.

Lua: Incorrect.

Me: Incorrect? What? Why?

Lua: Number of hats needed for each group is not known. 

That doesn’t make sense, right? It’s inconsistent.

But that seems like the method that the language-makers chose for reporting floats: talk in terms of Winnebagos in all cases except equivalence, and in the case of equivalence talk about hats.

I’m curious what the thought process is, what the logic is, behind that decision.