Computer Science and Irrational Numbers

It is quite rare that physical parameters are measureable, stable, and repeatable to more than a few decimal points of precision. So to answer the OP: We approximate.

Electrical engineers in particular tend to be satisfied with fairly course precision. We work with transistors who’s properties are specified only to slightly better than an order of magnitude, common resistors are +/- 5% (These days, they were +/- 20% a couple decades back). Good inductors and capacitiors might be 1%. So messing with more than two decimal places is silly. Representing pi as 3.14 will normally yield as good a result as you can hope for. I typically use three when doing stuff in my head.

OTOH, I’ve seen mechanical engineers doing stress analysis keeping 4-6 decimal places. Do they really think Young’s modulus in the physical hunk of material the part gets made from is going to be less than a percent off from the book value?

Arent there reall at least 2 problems here?

Pick any base. 2,3 10, 16 whatever. Different numbers will not be able be expressed as a finite decimal number depending on which base you use.

The other issue. Are integers really and truelly special numbers? If they are, then I can never quite tell you exactly where pi is on the real number line.

Yes, this can work, but requires some serious effort to keep it all straight when you have values with many different number of decimal positions (e.g. prices with 5 decimal positions, discounts with 3 decimal positions, final invoice amount in 2 decimal positions, then throw in multi-currency and it really gets complicated).

Well, there are numbers that can’t be described on the Straight Dope message board, even allowing for arbitrarily long posts (an enhancement which you would probably use to full advantage). In fact, most of them can’t (please don’t ask me to describe an example).

Assuming, that is, that a post can describe at most a countable number of distinct numbers.

And fixing a particular language in which to carry out the specification… every number is trivially describable according to some coding. Which is why I say indescribability is not a property of a number in itself. It’s a property of a number relative to a particular method of specification of numbers.

(It’s also only true on a “classical” account of what real numbers are and so forth, which may not be the most appropriate account in this context… But that’s a hard battle to wage. But I would note that Cantor’s diagonal proof is actually constructive; it gives us a description of the very process to take any map from N to (N -> 2) and produce a particular element of N -> 2 not in the range of that map. Which makes it difficult to non-paradoxically apply to yield the result “There exist sequences which are not describable in (a suitable idealization of) English”, or whatever.)

[Indeed, the computable world provides the greatest analogy for what’s going on here; Cantor’s diagonal proof applies there just the same as anywhere else, telling us there can be no computable surjection from the integers to the computable total functions from integers to bits. And, indeed, there cannot be. But this isn’t because there are “more” computable total functions from integers to bits than there are integers, not even in a computable sense. After all, there is a computable map from the integers to the computable partial functions from integers to bits which has every computable total function from integers to bits in its range [consider the function which sends the integer n to the partial function computed by the nth program taking integers as input and possibly producing bits as output]. It’s just that there’s no way to keep all those total functions in its range while getting rid of the accompanying partial functions. That is, you can devise a description system under which every element of 2^N is finitely describable, as long as you also allow that some finite phrases don’t describe elements of 2^N but elements of some superset of it instead, and you accept in your metalogic that it be needn’t be generally possible to affirmatively determine which these latter phrases are (thus precluding the opportunity to filter them out by assigning them default denotations).

I think the same analysis here as to what goes on with computable specifications is apt for what goes on with other forms of specification as well (e.g., in ordinary language), particularly in terms of what Cantor’s theorem should and should not be taken to imply. I admit it’s not a very mainstream position at the moment, but tradition has its inertia…]

But anyway, if you find all that unconvincing, feel free to ignore it. The far more important point is that you should never speak of a number, or anything, as though it were intrinsically, universally indescribable. You should only ever speak of description relative to a particular scheme for doing so.

Most programmers don’t.

The vast majority of numbers in computer programming are not only rational, but only need to be accurate to 2 decimal places. Because they are amounts, representing dollars and cents. Greater precision may be needed during calculations, but the end result will be presented (rounded or truncated) to 2 decimal places.



data Rational = Rational Int Int

...

oneThird = Rational 1 3
oneSeventh = Rational 1 7


Exact representations for 1/3 and 1/7 :wink:

Capt. Ridley’s Shooting Party: A lot of languages (Common Lisp, Scheme, Maxima, Mathematica, Maple, etc.) do represent rationals exactly and do math on their exact forms as much as possible. They even use arbitrary-size integers* to represent the numerator and denominator, giving their rationals a rather fearsome range and precision as long as you don’t care too much about speed or memory consumption.

*(Arbitrary-size integers are bounded only by the size of virtual memory. Arbitrary-precision real (irrational) numbers work by the same method. Both are very much adequate to most realistic tasks.)

I don’t agree. Unless you allow infinite descriptions of your coding (in which case you might as well allow infinite descriptions of numbers, in which case plain old decimal expansions will do just fine) you’ve got a finite description + a finite description = a finite description. If we consider a description to be a finite string over a finite alphabet, that’s a countable number of descriptions, which means a countable number of described numbers which leaves out most of the irrationals. Some (most) real numbers can not be described.

Yes, another one is Haskell, which uses a slightly more complex method than what I wrote in my post.

There are only a countable number of possible posts.

Only according to a twisted definition of “describe”. I say “There’s a number that can’t be described”, and you say “Sure it can: ‘ujn’ is my description of that number in a particular system of description”. Well, you haven’t described it. Now, if you will specify your method of description as well, then you can be said to have described it. But there are only a countable number of descriptions of methods. And so on.

Back to representation. Nobody cares that for every real number there is a way of representing it by, for example, declaring that a byte containing 42 represents that real. The question is whether any system of representation can represent all of them, or some range of them (e.g., -1e300 to 1e300). The answer, even allowing for infinite (but countable) memory, is “no”.

For countable subfields of the reals it can, of course, be done, whether for practical purposes (most likely) or because you’re a constructivist and deny the existence of the other reals (not likely to be a consideration). In some contexts it’s useful to represent the rationals, most commonly by using two integers, one for the numerator and the other for the denominator. It’s worth pointing out what symbolic mathematics programs do. But for most purposes we use a floating point representation, which doesn’t even form a field under the usual operations, but which has been found to be quite useful for general-purpose computations.

And that’s really the answer to the OP. Cauchy sequences, the continuum hypothesis, computability vs. definability, weak versions of the axiom of choice (and, naturally, their acceptability to constructivists)…we could go on all day, but we’d just be dumping core.

[aside]For those of you who feel even single precision reals are too dog-gone accurate, there’s a half precision real, available here (I found relevant (half*.*) files in openexr-1.4.0a.tar.gz, but nothing jumped out at me in a quick skim through the “latest stable version”.).

[further aside]I’ve often wondered why there was never a 6 byte 1.5 precision real made back in the 16 byte days, when memory was at a premium.[/further][/aside]

And (given a programming language) only a countable number of possible programs, so there’s only a countable number of possible real numbers that can be calculated using a program. So most real numbers cannot be calculated with any finite computer program.

(Of course, as the OP will have gathered by now, in practice programmers almost never really care that much about exact arithmetic, and just use the approximating arithmetic of floating-point or what have you. So if the OP does not want me to continue my very theory tangents and pedantry, I will oblige.)

And when I specify my method of how to interpret descriptions of numbers, will this have to come also with a blueprint for how to interpret such specifications of such methods? And then the instructions for reading blueprints, and so on? Explanations come to an end somewhere. A coding scheme is just a coding scheme; it exists independently of your ability to describe it (in English or whatever else [some other coding scheme for describing coding schemes]).

You are correct that, in any particular coding scheme, you can only specify countably many numbers. On some idealization of English, there are only countably many numbers specifiable in English. And so on.

The point I am making is that there’s no point looking at a number itself and considering it intrinsically specifiable or unspecifiable. It’s only specifiable relative to some particular coding scheme. Specifiable in Martian but not specifiable in English. This may seem nitpicky and pointless, but so far as the question of computer representation goes, I think it’s a fair point to bring up.

Because the computer doesn’t care about English language descriptions of correspondences between bitfields and numbers, or Martian language descriptions of such correspondences, or whatever. The computer just has bitfields and operates upon them. So it is pointless to say “This number can be represented on a computer, that number can’t” in isolation. The question is holistic; what are all the constants that you want to be able to represent and operations that you want to be able to compute upon those representations? Is there a way to set up a correspondence between those constants and particular bitfields as allows for this (and who cares whether that correspondence can be specified in English or Martian or what have you? The computer certainly doesn’t)?

Of course. Nobody cares because nobody should care about representation unless it comes along with some expectation of what one should be able to do with those representations. Sometimes, what one wants to be able to do with the representations is extract decimal notation expansions. Sometimes, one wants something else. Depending upon what one wants to be able to do, a method of representation is legitimate or not.

I agree. No fixed system of representation can distinctly represent every real number (classically). But that’s a property of the real numbers (and the ability to tell them distinct) as a whole; there are no particular real numbers which hold the property of nonrepresentability, because representability/nonrepresentability isn’t a property of numbers individually; it’s only a property of entire structures of constants and operations upon them.

Here is a blog post from another computer scientist (not me) whose particular specialty is in computer representation of real analysis (see here, here, or here, for examples of their work), that makes many of the same points I am making, but perhaps better; in particular, the emphasis on “It is meaningless to discuss representations of a set by a datatype without also considering operations that we want to perform on the set.”

I messed up the link to that post a little (it opens scrolled down a bit); here’s a better link.

I think it isn’t too unusual to treat a pair of numbers that, in principle, ought to get divided, but in practice are kept as integers for a while longer in the program. Perhaps this is because several things have to happen, and can happen first, and they are all much faster to do with integers than doubles, so postpone casting them to dbls and dividing them until you’ve done all the integer work you can. Or, perhaps this is because there can be an important rounding error or other ambiguity if you leave the calculationally perfect realm of the integers (at least the ones small enough to fit in the processor). In any case, this amounts to directly treating an effective number as rational, even if the programmer hasn’t thought of it that way.

By the way, the last time I read up on the '86/'87/Pentium FPU (floating point unit), the way it does division may surprise readers. First, it is always dividing two numbers that are (in decimal base) always greater than or equal to 1 and less than 2. This should be obvious, because in binary base, a floating point number, or more precisely and to the point for computers a number in scientific notation, is always like this, except multiplied by decimal 2 raised to an integer power. The task therefore is more simply to multiply the two numbers, and just add their two exponents, which of course are integers. So, the initial step is to look up approximations of the two numbers in a table. Yup, they’re hard coded in there, to a few binary places. Errors in this table were the exact form the famous “Pentium division bug” took. Then the processor uses Newton’s method or something similar to start estimating the remaining digits, by guessing - well, a sort of projection - what they are, and multiplying them, and then comparing the result with the givens, and projecting a better estimate from there. At least as of a few years ago, this was the fastest way to divide nonintegers in a practical FPU.

What slightly more complex method are you referring to? Isn’t what you wrote in your post exactly the typical way to deal with rationals in Haskell?

ETA: Oh, nevermind. You must mean by using (arbitrary size) Integer rather than (bounded size) Int.