Why Python is the best programming language in the world

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Why Python is the best programming language in the world

Postby korona » Tue Sep 24, 2013 2:21 pm UTC

ahammel wrote:A few things jump out at me comparing them:
[list]
General readability: Python is a bit better here. I think we can all agree that `if next_candidate in lazy_sieve' is a bit clearer than `if lazy_sieve.count(next_candidate)' (and can I point out that `count' is a pretty stupid name for a method that can only count to one?). The `yield' keyword is very handy for this particular algorithm in Python, but C++ doesn't have that, so I've had to do some slightly evil recursion magic that even the compiler complains about. Also `std::unordered_map<unsigned long, unsigned long> lazy_sieve'. I wrote it, and I can barely remember what the hell all that means.

std::unordered_map<unsigned long, unsigned long> looks very clear to me: It's a map that maps longs to longs.

Boilerplate: Python wins. Leaving aside the issue of the separation of variable instantiation in C++, there's a bit of language-specific weirdness in the implementation already that doesn't have much to do with the algorithm, particularly the header guard. I know the header guard isn't necessary, but it's a good idea if the program is ever going to be expanded beyond just printing primes.
Brevity: 42 non-trivial SLOC in the C++ vs 15 in the Python for similar or slightly better readability. Python wins.

The entire header file is not necessary. The Python implementation contains of a single function, it would be fairer to compare that to a C++ implementation that only consists of a single function. You could also strip a few lines consisting of variables declarations and closing braces only without decreasing readability. But of course your argument remains valid and C++ usually requires much more boilerplate than Python.

Int management: Python does it automatically, but it's a bit annoying in C++. The Python interpretation also has a slight advantage in that it will run until your exhaust either you memory or your patience, whereas I've had the C++ implementation error out once it gets to 18446744073709551615 rather than suffer an integer overflow. Sorry about that.

Other way to look at that: The Python implementation uses unnecessary large and complicated data types to store ints that cannot be properly optimized.

EDIT:
Memory management: perhaps surprisingly it's a tie. I haven't had to do any more explicit memory management in C++ than in the Python implementation, and it's valgrind-pure. I can't say as I understand exactly how everything gets cleaned up in my version, but then I don't understand how the Python garbage collector works either.

std::unordered_map has a non-trivial destructor that deletes the memory required to hold the hash map. When your class is destructed it implicitly calls this destructor.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Why Python is the best programming language in the world

Postby Jplus » Tue Sep 24, 2013 2:25 pm UTC

I think the thread title needs to change. It's really attracting too much discussion that the thread wasn't meant for, AFAICT.

troyp wrote:
Jplus wrote:Wait. C++ and Python are about equally strongly typed?

Python people always claim Python is "strongly typed". It's pretty much bullshit, of course. They're using a rather dodgy definition of "strongly typed" to mean something like "no implicit type casting".

Traditionally, strongly typed means "no unchecked type errors" or "cannot subvert the type system". But Python only has this form of strong typing with respect to its builtin types: user defined types can be unsafely cast simply by reassigning to the __class__ attribute. If the new and old classes share a method name and one or more attribute names, the new class method may interpret the original data in a way inconsistent with its original meaning (ie. an unchecked type error may occur.)

I suspect a lot of the confusion comes from people misusing "weak typing" to refer to Perl's use of implicit type conversion*. Since Python doesn't do this**, it must be "strongly typed".

* Perl-style casting isn't what I'd call weak typing at all: those conversions are semantically meaningful, eg. 65 -> "65". They're just normal, type-safe functions applied implicitly under certain conditions. Really, the kind of casting that indicates weak typing is a coercion which actually reinterprets the untyped data as a different type, eg. 65-> 'A'.
** Although Python uses operator overloading to convert between numeric types in operations, which ultimately has the same effect as implicit conversion, anyway.


Actually it seems that the strong/weak typed distinction is pretty dodgy anyway. One can better speak in terms of type safety. C++ is mostly type safe at compile time and Python is mostly type safe at runtime. That's to be expected as the former is statically typed and the latter is dynamically typed. I believe static vs. dynamic typing is the only fundamental difference between the two; Python is a bit more helpful when you overflow an integer, but that's about it. Then, duck typing is optional in C++ and there are no templates in Python, but there's no point in having templates in a dynamically typed language anyway.

Anyway, while I think C++ isn't really stronger typed than Python, I think it certainly isn't weaker typed, so I still don't understand why Alex considered that a win for Python. :P

Note that I really prefer static typing. I just consider strong/safe typing as something that is mostly orthogonal.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Python: Fleeting Thoughts ;-)

Postby troyp » Tue Sep 24, 2013 5:05 pm UTC

Jplus wrote:I think the thread title needs to change. It's really attracting too much discussion that the thread wasn't meant for, AFAICT.

Python: Fleeting Thoughts ;-)
Actually it seems that the strong/weak typed distinction is pretty dodgy anyway. One can better speak in terms of type safety.

True, it's pretty much useless trying to talk about strong typing at this point. Still, the term has often been used in papers on programming languages/type systems with meanings along the lines of "can't subvert the type system", so I feel it's worth trying to defend that meaning to avoid further confusion. I do think it's better to use another term from now on.
Anyway, while I think C++ isn't really stronger typed than Python, I think it certainly isn't weaker typed, so I still don't understand why Alex considered that a win for Python. :P

Well, there are more holes in the C++ type system. I said before that you can violate Python's user-defined types, but it's more likely to happen in C++ (or C especially, due to lack of higher-level abstractions). In C++ you can do it with primitive types even: you can reinterpret the bits of an integer as a float, or whatever. That can't happen in Python.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Why Python is the best programming language in the world

Postby Jplus » Tue Sep 24, 2013 6:48 pm UTC

Well C is probably less type safe than Python, with implicit casts between any pair of pointer types. You can reinterpret data in C++, but the very fact that you have to ask for it very explicitly shows that the type system doesn't normally allow it, as far as I'm concerned. Also, to compensate for the fact that Python doesn't allow it on builtin types, C++ offers static type checking.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
hotaru
Posts: 1045
Joined: Fri Apr 13, 2007 6:54 pm UTC

Re: Python: Fleeting Thoughts ;-)

Postby hotaru » Tue Sep 24, 2013 8:39 pm UTC

troyp wrote:In C++ you can do it with primitive types even: you can reinterpret the bits of an integer as a float, or whatever. That can't happen in Python.

can't happen? i don't think so...

Code: Select all

>>> from ctypes import *
>>>
 i = int(42)
>>>
 cast(pointer(c_int(i)), POINTER(c_float)).contents.value
5.885453550164232e-44

Code: Select all

factorial product enumFromTo 1
isPrime n 
factorial (1) `mod== 1

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Tue Sep 24, 2013 11:45 pm UTC

That's not reinterpreting a Python builtin, though - it's reinterpreting a C type.

AFAICT, c_int is a perfectly type safe function that maps a python int to a c_int. It's the c_int that's reinterpreted. You can see this by doing

Code: Select all

c_float(int(42))
The c_float function isn't reinterpreting the bit pattern of the integer, it's just converting it to float normally. Likewise, c_int(i) is just using i's integer value, not looking at its representation.

Having said that, for all I know, there could be some C module that lets you violate the Python base types. I wasn't really thinking of that. It seems more like an escape hatch in the type system than a hole (although that's admittedly subjective). I'm curious if you can do it, though.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Why Python is the best programming language in the world

Postby ahammel » Wed Sep 25, 2013 12:22 am UTC

phlip wrote:Yeah... that isn't quite going to do what you hope. "If the value in this unsigned long variable is larger than the maximum value that can be stored in an unsigned long variable..."
Haha, whoops! I could've sworn that tested for equality at one stage.
korona wrote:The Python implementation contains of a single function, it would be fairer to compare that to a C++ implementation that only consists of a single function.
I don't know how to write a single function in C++ that returns a prime number generator1. If there's a clean way to do it, then I agree that would be a fairer comparison.

My goal was to write it in the way that you would if you were going to integrate it into a larger program. I'd be perfectly happy to drop the Python version into a module as-is, but my understanding is that the C++ convention in that situation is to separate the interface and the implementation, so that's what I did.
Jplus wrote:Anyway, while I think C++ isn't really stronger typed than Python, I think it certainly isn't weaker typed, so I still don't understand why Alex considered that a win for Python. :P
Mostly because I was thinking of this:
Jplus wrote:Well C is probably less type safe than Python, with implicit casts between any pair of pointer types.
But, of course, you can't do that C++, so call that one a draw as well :P

I don't really consider it a flaw that it's possible to subvert the type system in both languages, just so long as doing so requires obvious devil-magic.

To bring things back to examples of Python coolness: SCons seems like it should count. I think it's pretty neat to have your build-system synatx built on top of an already excellent scripting language (viz, Python).

1. One could make the argument that I don't really know how to do it with classes either.
He/Him/His/Alex
God damn these electric sex pants!

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Python: Fleeting Thoughts ;-)

Postby EvanED » Wed Sep 25, 2013 12:55 am UTC

troyp wrote:True, it's pretty much useless trying to talk about strong typing at this point. Still, the term has often been used in papers on programming languages/type systems with meanings along the lines of "can't subvert the type system", so I feel it's worth trying to defend that meaning to avoid further confusion. I do think it's better to use another term from now on.
My opinion is the opposite. "Strongly typed" has often been used in roughly three very different ways: (1) how much can the type system be subverted, (2) static vs dynamic, and (3) how restrictive your type system is. (For example, under the third definition, Haskell and ML are very strongly typed (you can't even say 1+1.0), Perl and PHP are very weakly-typed (1 + "1" anyone?), and Python and C++ are somewhere in the middle.) All three are spectrums -- or really, not even a total order necessarily.

But the first two already more or less have perfectly good terms: (1) is type safety and (2) is, well, statically/dynamically-typed. The third, however, doesn't really have another term I'm familiar with. You could invent something like "type restrictiveness" or something, but with as common of a term "strongly typed" is for that, I think it is probably the best choice of a bunch of not-very-compelling choices.

hotaru wrote:
troyp wrote:That can't happen in Python.

can't happen? i don't think so...

Code: Select all

>>> from ctypes import *
>>>
 i = int(42)
>>>
 cast(pointer(c_int(i)), POINTER(c_float)).contents.value
5.885453550164232e-44

Depends on what you (or troyp) means by "Python". It's reasonable to say it can't happen in Python-the-language: ctypes isn't guaranteed to exist, and on some Python implementations it probably is impossible to subvert the type system.

Incidentally, and somewhat unrelated but pretty damn amazing (I've probably posted this before, but whatever):

Code: Select all

>>> import sys
>>> import ctypes
>>> pyint_p = ctypes.POINTER(ctypes.c_byte*sys.getsizeof(5))
>>> five = ctypes.cast(id(5), pyint_p)
>>> five.contents[five.contents[:].index(5)] = 4
>>> 5+0
4
>>> 5+1
4
>>> 5+2
6

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Why Python is the best programming language in the world

Postby Nyktos » Wed Sep 25, 2013 1:55 am UTC

ctypes isn't the only way to do type punning in Python.

Code: Select all

>>> struct.unpack("@f", struct.pack("@i", 42))[0]
5.885453550164232e-44


As far as "strongly typed" goes, when people use in in reference to Python they mostly just mean it doesn't do insane PHP/JavaScript-style loose typing shenanigans. It's a fairly imprecise usage but the term is poorly defined to begin with, and that is a noticeable difference between Python and a number of other dynamic languages.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Python: Fleeting Thoughts ;-)

Postby Jplus » Wed Sep 25, 2013 8:16 am UTC

EvanED wrote:"Strongly typed" has often been used in roughly three very different ways: (1) how much can the type system be subverted, (2) static vs dynamic, and (3) how restrictive your type system is. (For example, under the third definition, Haskell and ML are very strongly typed (you can't even say 1+1.0), Perl and PHP are very weakly-typed (1 + "1" anyone?), and Python and C++ are somewhere in the middle.) All three are spectrums -- or really, not even a total order necessarily.

But the first two already more or less have perfectly good terms: (1) is type safety and (2) is, well, statically/dynamically-typed. The third, however, doesn't really have another term I'm familiar with. You could invent something like "type restrictiveness" or something, but with as common of a term "strongly typed" is for that, I think it is probably the best choice of a bunch of not-very-compelling choices.

How about calling (3) "firmly typed" vs "loosely typed"?

Note that very loosely typed languages like Perl and Javascript are also less type safe. The program has no guarantee that the string you're going to add to an integer represents a valid number. In addition, it means that the language doesn't catch reasoning errors since the operation might be addition while the programmer expected concatenation, or vice versa.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Python: Fleeting Thoughts ;-)

Postby EvanED » Fri Sep 27, 2013 1:51 am UTC

Jplus wrote:Note that very loosely typed languages like Perl and Javascript are also less type safe.
I was going to disagree but I think the matter is something I hadn't really realized before, which is that I'd say that the entire type safety spectrum is largely meaningless when it comes to dynamic languages. For instance, 1 + "1" producing 2 or "12" isn't any more unsafe than causing a TypeError to be raised, because both are well-defined operations specified by the language semantics.

Let's flip things around and look at the situation for static languages. Either of those results are possible for a static language as well. For example, in Java, 1 + "2" evaluates to "12" while in C++, 1 + std::string("2") is not allowed (I hope :-)). But in this situation, I'd say definitely both options are type safe. It would only be not typesafe if 1 + std::string("2") was not allowed in the sense of producing undefined behavior but the type checker didn't catch it anyway. For example, 2 + "1" would be allowed by the type checker but still is outside the scope of the semantics of the C++ language; this is debatably not type safe (depending on whether you consider that a type error).

In other words, a language is type safe if the type checker is able to prove the absence of a certain class of bugs called "type errors." But... dynamic languages don't have a type checker, so there's nothing to reject such programs! With no type checker, applying the term "type safe" or "not type safe" doesn't even really make sense.

However, throwing a runtime error is a bit like rejecting the program. In that case, a language that is more restrictive, e.g. Python rejecting 1 + "2", is behaving a little like the dynamic equivalent of a type checker rejecting a program.

There're a lot of aspects of this analogy that don't match up, but hey, that's why it's an analogy. :-) And it's an aspect of this that I hadn't really thought about before.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Fri Sep 27, 2013 2:30 am UTC

I had a reply to various posts, but it became too long and I got guilty about derailing the thread with off-topic ramblings*. So I put it in a new thread.

* Not the thread has ever really had that much of a topic, but I managed to get off it anyway

@EvanED: I mentioned this in the other thread, but I think implicit coercions are type safe as long as they don't rely on the representations of the types. (You could construct an example where they do violate a "type", but only if the type was an implicit one - ie. a type distinction in the mind of the programmer, but not in the actual type system of the language.) The way I see it, if you changed the way Perl/JS/whatever represented ints (or floats for JS), the implicit conversions would still give the same results: the operations are based on the value itself, not its internal representation.

As you said:
EvanED wrote:It would only be not typesafe if 1 + std::string("2") was not allowed in the sense of producing undefined behavior but the type checker didn't catch it anyway. For example, 2 + "1" would be allowed by the type checker but still is outside the scope of the semantics of the C++ language; this is debatably not type safe (depending on whether you consider that a type error).

The consequence of "not being allowed" is that there's no way to know how to even perform the operation. ie. the only way is by just reinterpreting the underlying untyped data. IMO, that's the essential thing that violates type safety.

aside: I just noticed the "Python: Fleeting Thoughts" heading I used earlier has been virally propagating via the reply mechanism. lol. I didn't realise that happened.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Why Python is the best programming language in the world

Postby ahammel » Fri Oct 04, 2013 12:41 am UTC

I was doing some pretty cool things with regexes and string formatting today.

Code: Select all

import re

FILE_NAME_REGEX = re.compile("""
        (?P<id>[0-9A-Z]{9})          # ID number
        _                            # Underscore separator
        (?P<batch>\d{1,2})           # Batch number
        _                            #
        (?P<date>\d{4}-\d{2}-\d{2})  # Date created
        (?P<ext>\.txt                # Extension
         (?:\.bz2){0,1})             # Optional compression
        """, re.VERBOSE)


class BadFileNameError(Exception):
    __doc__ = """
    Raised when the file name does not match the following regular
    expression::

        {0}

    """.format(FILE_NAME_REGEX.pattern)


def modify_file_name(file_name):
    """Performs some manipulations to the file name.

    """
    new_field_in_file_name = "foo"
    match = FILE_NAME_REGEX.match(file_name)
    if not match:
        raise BadFileNameError("Bad file name: {}".format(file_name))
    return "{id}_{new_field}_{batch}_{date}{ext}".format(
            new_field = new_field_in_file_name,
            **match.groupdict())
He/Him/His/Alex
God damn these electric sex pants!

User avatar
skeptical scientist
closed-minded spiritualist
Posts: 6142
Joined: Tue Nov 28, 2006 6:09 am UTC
Location: San Francisco

Re: Why Python is the best programming language in the world

Postby skeptical scientist » Fri Oct 04, 2013 9:08 pm UTC

One thing I love about python is how easy generator expressions make it to transform between different representations of the same information. A quick example:

Code: Select all

def NumberSetToHexString(number_set):
    return "0x%x" % sum(2**n for n in number_set)
I'm looking forward to the day when the SNES emulator on my computer works by emulating the elementary particles in an actual, physical box with Nintendo stamped on the side.

"With math, all things are possible." —Rebecca Watson

User avatar
thoughtfully
Posts: 2253
Joined: Thu Nov 01, 2007 12:25 am UTC
Location: Minneapolis, MN
Contact:

Re: Why Python is the best programming language in the world

Postby thoughtfully » Sat Oct 05, 2013 12:05 am UTC

I hadn't thought of anything I wanted to post to this thread, but you just reminded me of a neat little snippet I have. There's much setup and support, but the juicy stuff is pretty terse :)

Code: Select all

def ln2(n):
   if n<0:
      raise ValueError('math domain error')

   i = 0
   n = int(ceil(n))
   while n:
      i += 1
      n >>= 1

   return i

_fmtinner = ('',' ') * 3 + ('','-') + ('',' ') * 3 + ('','')
_fmtouter = ('  ', '  |', '|')

def _mkhex(d, i):
   try:
      return '%02x' % (ord(d[i]),)
   except IndexError:
      return '  '

def _mkchar(d, i):
   try:
      c = d[i]
      if 31 < ord(c) < 127:
         return c
      else:
         return '.'
   except IndexError:
      return ' '

# n is the number of digits in the address field, minimum is two.
# length of each line is 63, for n<3, then one more character for each n>=3
def prettify_binary(data, n=None):

   inputsize = len(data)
   if not n:
      n = ln2(max(0, inputsize-1), 4)

   lines, rmdr = divmod(inputsize, 16)
   if rmdr:
      lines += 1

   return '\n'.join([''.join(kk) for kk in [sum(zip(k, _fmtouter),()) for k in [
      [ '%%0%dx0' % (n-1,) % (i,),
        ''.join(sum(zip([_mkhex(data, 16*i+j) for j in range(16)], _fmtinner), ())),
        ''.join([_mkchar(data, 16*i+j) for j in range(16)])
      ] for i in range(lines)] ]])

if __name__ == '__main__':
   import sys
   print prettify_binary(sys.stdin.read())

Code: Select all

0 % dd if=/dev/urandom bs=16 count=8 |python prettybin.py
00  5372 f4e4 56fa 1706-700e 75c9 967f ade6  |Sr..V...p.u.....|
10  3bfe 94ad 6d54 baa6-6ced a5af 3f23 c962  |;...mT..l...?#.b|
20  8e8b 2b56 f089 5ade-b29c 0085 7ddd 4fe6  |..+V..Z.....}.O.|
30  7046 2fd1 a068 edeb-b8b2 de90 0fde 35d2  |pF/..h........5.|
40  bd67 66e9 e2cd 860b-0b1a dd05 cd87 82ed  |.gf.............|
50  04b5 2c7c e626 0d3d-b78e 6e12 6def 013d  |..,|.&.=..n.m..=|
60  c304 d70a 9468 f7bb-24c8 abbd 1000 be31  |.....h..$......1|
70  8d1e 3274 963e ba62-f225 dfd2 a2de c0de  |..2t.>.b.%......|

I might as well pass along the hexdump format file as well. Only slightly less unsightly than sendmail configuration.

Code: Select all

"%04_ax  "
2/1 "%02x" " " 2/1 "%02x" " " 2/1 "%02x" " " 2/1 "%02x" "-" 2/1 "%02x" " " 2/1 "%02x" " " 2/1 "%02x" " " 2/1 "%02x"

"  |"

16/ "%_p"

"|\n"
Image
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sat Oct 05, 2013 12:51 pm UTC

skeptical scientist wrote:One thing I love about python is how easy generator expressions make it to transform between different representations of the same information.

They come from set notation (via Haskell list comprehensions), you know.

thoughtfully wrote: n = int(ceil(n))

Don't you hate that? I know it's a stupid thing to complain about, but it really bugs me (especially since I don't have a better name for an integer version than "int_ceil" or "round_up".*) I've never understood why ceil and floor return floats in the first place. Aren't you almost always going to want integers?
* or "ceiling", which is fine in itself, but it seems kinda weird and arbitrary having both names, with one assigned to a float-returning function and the other an int-.

User avatar
thoughtfully
Posts: 2253
Joined: Thu Nov 01, 2007 12:25 am UTC
Location: Minneapolis, MN
Contact:

Re: Why Python is the best programming language in the world

Postby thoughtfully » Sat Oct 05, 2013 1:20 pm UTC

Python is following the C standard library with that. Complain to K&R.
Image
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Why Python is the best programming language in the world

Postby lalop » Sat Oct 05, 2013 3:52 pm UTC

troyp wrote:I've never understood why ceil and floor return floats in the first place. Aren't you almost always going to want integers?

Consider: If floor() returned an integer, what should floor(1.0e30) return?

- http://stackoverflow.com/a/8582794/1732572


Contrary to what the rest of that submission says, I doubt having arbitrary-precision integers actually makes any difference. There's still no sensible integral answer to floor(1.0e30) (or any floating point number with too large an exponent for the mantissa to contain the integer value). The only sensible answer is 1.0e30.

User avatar
phlip
Restorer of Worlds
Posts: 7573
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Why Python is the best programming language in the world

Postby phlip » Sat Oct 05, 2013 4:31 pm UTC

thoughtfully wrote:Python is following the C standard library with that. Complain to K&R.

That's an explanation, but not an excuse... same as the C API isn't really an excuse for PHP having mysql_real_escape_string, for instance. The language should do what makes sense for the language, not blindly follow other languages... and for a language that has native bigints, that includes floor() and ceil() returning ints/longs (maybe with different functions in another module to return floats for edge cases where maybe you somehow want that).

floor(1e30) should return the same as long(1e30) (ie a number close to, but probably not exactly, 1000000000000000000000000000000L), and I don't see a convincing argument why it shouldn't. If your concern is rounding errors, well then you should've thought of that before you started using floats, and having floor return an int isn't going to introduce additional rounding errors you don't have already.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Why Python is the best programming language in the world

Postby lalop » Sat Oct 05, 2013 5:44 pm UTC

floor(1e30) = 1e30 is the "least wrong" answer. In fact, it is undeniably correct, whereas assuming that the remaining mantissa digits are all zero would effectively be an implementation detail.

long(..), on the other hand, does not have to satisfy any mathematical correctness. In fact, as a type, it effectively is an implementation detail, so making up that it's the long just less than that floating point number is okay.

Effectively, one is "least wrong" while the other is "least long". Ho ho.. I'll see myself out.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sat Oct 05, 2013 6:17 pm UTC

lalop wrote:
Consider: If floor() returned an integer, what should floor(1.0e30) return?

- http://stackoverflow.com/a/8582794/1732572

Contrary to what the rest of that submission says, I doubt having arbitrary-precision integers actually makes any difference. There's still no sensible integral answer to floor(1.0e30) (or any floating point number with too large an exponent for the mantissa to contain the integer value). The only sensible answer is 1.0e30.

No, it's not. There is no sensible answer (except an approximate one). It makes no sense to take the floor or ceiling of a number that's not precise enough to fall within two integers! And even if you wanted to do it anyway, you couldn't be sure it comes to 1.0e30...the floor could come to 9.9...9e29, or the ceiling to 1.0...01e30. I don't think returning 1.0e30 is any more correct than a bigint would be (although it's certainly far more efficient, which I guess is the point).

Nevertheless, that rationale does make sense on a practical level. You might want to calculate some formula involving ceil or floor, where you need precise results for low n and approximate results for large n. Having them return floats would let you code that function concisely and efficiently. So there's actually a good reason to have a float-returning floor/ceil.

That still doesn't explain the lack of integer ones, though! C has an integer division function, for example, so I'm not sure why it has no integer floor/ceil functions (especially when those operations are primarily integer functions). And the very fact that the floating point functions accept large floats is actually another reason why you need integer versions. Casting a float result to int isn't enough since you can't be sure you'll get the right answer.

Oh well. Thanks for the explanation, anyhow. At least now I know there's some kind of logic behind it. Maybe I'll even remember they return floats now, instead of being surprised and annoyed by it every time...

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Why Python is the best programming language in the world

Postby ahammel » Sat Oct 05, 2013 6:20 pm UTC

Consider: If floor() returned an integer, what should floor(1.0e30) return?

- http://stackoverflow.com/a/8582794/1732572
A TypeError?
He/Him/His/Alex
God damn these electric sex pants!

User avatar
jestingrabbit
Factoids are just Datas that haven't grown up yet
Posts: 5967
Joined: Tue Nov 28, 2006 9:50 pm UTC
Location: Sydney

Re: Why Python is the best programming language in the world

Postby jestingrabbit » Sat Oct 05, 2013 7:01 pm UTC

Or OverflowError, or something that actually tells you what just happened, and gives you a value if you actually want it.
ameretrifle wrote:Magic space feudalism is therefore a viable idea.

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Why Python is the best programming language in the world

Postby lalop » Sun Oct 06, 2013 12:51 am UTC

troyp wrote:you couldn't be sure it comes to 1.0e30...the floor could come to 9.9...9e29, or the ceiling to 1.0...01e30.


Ah yes, I guess I was premature in saying it was always correct. I think this is still the "least wrong" answer, however: it's correct except in unavoidable, scattered ranges that get asymptotically less likely as the number gets bigger. Alternatively, if a floating point number is thought of as a range of numbers, it's correct for "most of" that range ("most" asymptotically approaching "all").

I would not mind some kind of ToleranceError or UndefinedError either, just so long as it did not just silently revert to a hidden assumption. (And, you would get ints that way, yay!) I'm not sure how annoying it would be to check for errors whenever you use floor, however.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sun Oct 06, 2013 7:43 am UTC

lalop wrote:I'm not sure how annoying it would be to check for errors whenever you use floor, however.

It shouldn't be too hard to do (although specifying it is another matter). I noticed before looking at math.h that there are functions for the previous/next representable floats, so you could just test if the difference between consecutive floats is less than epsilon.

What's epsilon, though? 1? 0.25? 0.0001? It's kind of arbitrary really.

Actually, I think Phlip's right. Maybe it's better, even for an int-returning floor/ceil, to just return bignums if you have them (and if you don't, throw an overflow error when the number's too big). Issues with precision are an unavoidable part of using floats - it's pointless even to try to address them in a library function*. Leave it to the client.
*unless there are some standard conventions for handling precision and errors in floats I'm unaware of.

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Why Python is the best programming language in the world

Postby lalop » Sun Oct 06, 2013 9:06 am UTC

It depends on the model we're using to represent numbers with floats, I think. Assuming the "truncation model" (we truncate real numbers to get floats), current-float can represent any number from current-float to next-float, so it suffices to determine whether or not long(current-float) == long(next-float) for getting a singular answer.

On the other hand, assuming the "rounding model", current-float can represent any number average(previous-float,current-float) ≤ n < average(current-float,next-float). Definitely a bit more complicated to check there; those averages would need to be turned into something that could be casted, for one thing.

troyp wrote:Actually, I think Phlip's right. Maybe it's better, even for an int-returning floor/ceil, to just return bignums if you have them (and if you don't, throw an overflow error when the number's too big). Issues with precision are an unavoidable part of using floats - it's pointless even to try to address them in a library function*. Leave it to the client.


Ironically, that is the exact same rationale I'd use for not returning bignums. The library should not be forcing any implementation detail (assuming the rest of the mantissa is zeroes). Instead, throw an error and leave it for the client to decide.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sun Oct 06, 2013 9:35 am UTC

(This thread's getting off topic again... I don't know why I always seem to be involved but I'm sure it's just a coincidence...)
lalop wrote:On the other hand, assuming the "rounding model", current-float can represent any number average(previous-float,current-float) ≤ n < average(current-float,next-float). Definitely a bit more complicated to check there; those averages would need to be turned into something that could be casted, for one thing.

Ugh. I momentarily forgot they weren't equispaced. That would be more of a hassle.

Ironically, that is the exact same rationale I'd use for not returning bignums. The library should not be forcing any implementation detail (assuming the rest of the mantissa is zeroes). Instead, throw an error and leave it for the client to decide.

But isn't the same issue there for small floats? If you have a float 2.0, how do you know if it's actually above 2, with floor=2, or below 2 with floor=1? (This is assuming your rounding model - but assuming the truncation model, we get a similar issue with ceil(2.0))

Large floats exaggerate the issue in that even if you had a float that actually represented an int, you wouldn't know which one it represented...but for any float that lies very close to an int, you don't know the right answer for floor/ceil.

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Why Python is the best programming language in the world

Postby korona » Sun Oct 06, 2013 10:27 am UTC

What is a float? A float is a number of the form a = a0 * 2s + a1 * 2s-1 + a2 * 2s-2 + ... + as-m+1 2s-m+1 where ai are in {0, 1}, s is the "exponent" of the number and m is the length of the mantissa. The only sane thing that floor can do is set a_i to zero if (s - i) < 0.

It also makes sense that floor returns a float because converting to int involves computing the expression above which is an unrelated task. If you wanted to use the result of floor in a float expression it would have to be converted to float again. Both operations are non-trivial, especially for big-ints and involve a noticeable runtime cost.

If you want floor to return an int and throw an error if |a| > 2m - 1 (i.e. the largest int number that can be represented by a float before the first "gap") you can simply define such a function yourself. All floats greater than this number represent integers exactly. Just not all integers greater than this number can be represented by a float. If you think of floats in this way the result of floor is not approximately correct but really correct.

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Why Python is the best programming language in the world

Postby lalop » Sun Oct 06, 2013 11:06 am UTC

Hmm, I guess throwing errors for floor(2.0) would not exactly be desirable.

korona's seems the sanest explanation overall.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sun Oct 06, 2013 11:20 am UTC

Yeah, but that's not a very useful way to look at floats. Then you don't even have floats for most numbers. The whole point is to represent a huge range of numbers, but with limited precision.

You know, I often think it would be nice if Python had builtin fixed-point (with a literal notation, etc). Then you could have functions ceil,floor: fixpoint->int and fceil,ffloor: float->float, which would cover the use cases nicely. We use floats a lot when we don't actually want them because we don't have convenient fixed-point. (Sure, they're trivial, but for something like this, a literal notation is essential - and so is standardization.)

edit: Oops, I mean fixed-point number, not fixnum. Corrected.

User avatar
thoughtfully
Posts: 2253
Joined: Thu Nov 01, 2007 12:25 am UTC
Location: Minneapolis, MN
Contact:

Re: Why Python is the best programming language in the world

Postby thoughtfully » Sun Oct 06, 2013 11:59 am UTC

There's Rational Numbers in the Standard Library now, as the fractions module. Fixed point is just a rational number with a power of two as the denominator. I seem to recall some inconvenient behavior, but that might have been the decimal module. That thing just makes my brain hurt for some reason. Too much time close to the metal, I imagine.
Image
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Why Python is the best programming language in the world

Postby korona » Sun Oct 06, 2013 12:21 pm UTC

Fractions are a nice way to approximate real numbers (because operations on them return exact results) but they are also suffer from problems: Normalization is slow because to normalize a fraction you have to compute the gcd of the numerator and denominator. Furthermore their memory requirement depends on the number stored; storing 1/2^n requires n bits.

Fixed point numbers are good for storing numbers that come from a small interval. The canonical example is money.

Floats are a good choice when the numbers come from a large interval, precision is not that important but computations have to be fast, for example when you specify 3D geometry in a computer game.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sun Oct 06, 2013 2:10 pm UTC

Rationals are nice, but I'm happy to have them in a library. It's nice to have rational literals in Lisp where you can use the standard notation, but in Python you couldn't do that anyway. You could have some convenient literal notation for fixed-point, though. Maybe 30.4. (or whatever)

korona wrote:Fixed point numbers are good for storing numbers that come from a small interval. The canonical example is money.

We often use numbers in a relatively small range, though. If we had 64-bit fixed-point, we could have 9 or 10 digits before and after the point. That kind of range and accuracy would be enough for a lot of uses. I reckon we'd use fixed-point as much as float if we had them. Maybe more.

Floats are a good choice when the numbers come from a large interval, precision is not that important but computations have to be fast, for example when you specify 3D geometry in a computer game.

Would fixed-point be much slower? I'd expect binary fixed-point to be as fast as floats. Decimal fixed-point (which I'd prefer) would be slower on multiplications since you'd have to divide by 10^k, but still fast on addition.

I think something like out-of-the-box decimal fixed-point with a literal notation would be a great fit for Python, since it lets people use the kind of numbers they're most familiar with (and that can be reasoned about easily). They follow the straightforward, easy-to-understand ethos of Python. Floats solve an important problem, but I wouldn't call them "straightforward".

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Why Python is the best programming language in the world

Postby korona » Sun Oct 06, 2013 2:26 pm UTC

troyp wrote:
Floats are a good choice when the numbers come from a large interval, precision is not that important but computations have to be fast, for example when you specify 3D geometry in a computer game.

Would fixed-point be much slower? I'd expect binary fixed-point to be as fast as floats. Decimal fixed-point (which I'd prefer) would be slower on multiplications since you'd have to divide by 10^k, but still fast on addition.

I think something like out-of-the decimal fixed-point with a literal notation would be a great fit for Python, since it lets people use the kind of numbers they're most familiar with (and that can be reasoned about easily). They follow the straightforward, easy-to-understand ethos of Python. Floats solve an important problem, but I wouldn't call them "straightforward".

Binary fixed-point numbers would be faster than floats because addition and multiplication are easier and division by 2^k would be a simple right shift.

But fixed-point numbers are not that great if some of your numbers are very large (e.g. ~10^5) while other are very small (e.g. ~10^-5) which is not uncommon for example in 3D computer graphics. They also suffer from precision issues when your numbers are close to zero.

User avatar
thoughtfully
Posts: 2253
Joined: Thu Nov 01, 2007 12:25 am UTC
Location: Minneapolis, MN
Contact:

Re: Why Python is the best programming language in the world

Postby thoughtfully » Sun Oct 06, 2013 2:36 pm UTC

troyp wrote:Would fixed-point be much slower? I'd expect binary fixed-point to be as fast as floats. Decimal fixed-point (which I'd prefer) would be slower on multiplications since you'd have to divide by 10^k, but still fast on addition.


Fixed point binary can be done almost as fast as integer math. They're integers with the "binary point" shifted.
Image
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Why Python is the best programming language in the world

Postby troyp » Sun Oct 06, 2013 6:07 pm UTC

I know, that's what I meant. Addition is just integer addition and multiplication is integer multiplication and right shift. But I figured there wasn't much overhead on float math either, since they're binary as well and they have hardware support. Apparently not, though. (I don't know the details of floating point arithmetic and trying to work it out seemed like a pain the arse so I didn't even bother. It didn't seem immediately implausible that it could be as fast as integer arithmetic of the same size)

User avatar
thoughtfully
Posts: 2253
Joined: Thu Nov 01, 2007 12:25 am UTC
Location: Minneapolis, MN
Contact:

Re: Why Python is the best programming language in the world

Postby thoughtfully » Sun Oct 06, 2013 7:01 pm UTC

Heh, kids these days. Back in the day, we had to do floating point math in software, it wasn't even supported by the processors. And it was slow!

Heck, it often still isn't if you're working with microcontrollers and such.
Image
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 8 guests