Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-21 Thread Ketil Malde

 fact 0 = 1
 fact n = n * fact (n-1)

 Now I ran it as fact 100 with signature Int - Int and with
 Integer - Integer

 In the first case I got 0 in about 3 seconds
  [...]
 And if that sounds like a unreal argument, consider representing and
 storing Graham's number.

So, since computers are finite anyway, we can just arbitrarily (well,
almost) redefine large constants, and set all factorials above some
threshold to zero?  Perhaps we should also set pi=3, that would simplify
lots of things :-)

 Pragmatically: 32-bits is unwise for a bank-balance, 64 should be a
 bit more safe

Please start a bank using modulo arithmetic, I'm looking forward to
overdrafting my account!  

 So yes, Haskell's Int, should have been called FastInt or Int29 or somethin'

On a more serious note, I accept that Int (and other limited precision
numbers) is a fact of life, and sometimes useful for performance
reasons.  

I would have liked, however, to have a compiler option or some other way
to make my programs throw an exception on overflow - even if this turned
out to be slower, I could at least use it when testing my programs,
which would have caught a few bugs.

-k
-- 
If I haven't seen further, it is by standing in the footprints of giants

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-21 Thread Rustom Mody
On Wed, Aug 21, 2013 at 11:47 AM, Ketil Malde ke...@malde.org wrote:
 On a more serious note, I accept that Int (and other limited precision
 numbers) is a fact of life, and sometimes useful for performance
 reasons.

 I would have liked, however, to have a compiler option or some other way
 to make my programs throw an exception on overflow - even if this turned
 out to be slower, I could at least use it when testing my programs,
 which would have caught a few bugs.

Yes for software detection, some will want it and some will not; see
the same discussion a few months ago
http://www.haskell.org/pipermail/haskell-cafe/2013-June/107153.html

The 'some other way' is hardware detection.  And there is glimmer of
hope that Intel may begin to do due diligence
http://www.emulators.com/docs/LazyOverflowDetect_Final.pdf

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-21 Thread Evan Laforge
 but Integer is actually (if you're using GMP with your ghc):

 Yes, that's tolerably well known.  You only pay the space overhead
 when you need it (like Lisp or Smalltalk).  But you always pay the
 time overhead.

I thought Integers can't be unboxed, regardless of their magnitude?

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-20 Thread Rustom Mody
On Tue, Aug 20, 2013 at 6:37 AM, Richard A. O'Keefe o...@cs.otago.ac.nz wrote:

 On 20/08/2013, at 3:43 AM, Kyle Miller wrote:

 On Sun, Aug 18, 2013 at 8:04 PM, Richard A. O'Keefe o...@cs.otago.ac.nz 
 wrote:
 The argument for twos-complement, which always puzzled me, is that the other
 systems have two ways to represent zero.  I never found this to be a problem,
 not even for bitwise operations, on the B6700.  I *did* find abs x  0
 succeeding to be a pain in the posterior.  (The B6700 had two different 
 tests:
 'are these two numbers equal' and 'are these two bit patterns equal'.)

 I think a better argument for twos complement is that you're just doing all 
 of your computations modulo 2^n (where n is 32 or 64 or whatever), and 
 addition and multiplication work as expected modulo anything.

 To me, that's not a better argument.

These kinds of argument usually come down to a question of framing --
whether pragmatic, philosophical or pedagogical.  Let me start with
the philosophical

 It isn't even a _good_ argument.
 It amounts to saying if you do things wrong, you can justify it by
 saying you're really doing something else right, and it's the programmer's
 fault for wanting the wrong thing.

This argument works if 'doing something right' is an available option.
 What if its not?


 One great thing about the B6700 was that you were guaranteed
 EITHER the mathematically correct answer in the numbers you were
 thinking in terms of OR an exception telling you the machine couldn't
 do what you wanted.  When it comes to *applications* programming,
 the number of times I have *wanted* arithmetic modulo 2^n (in the last
 40 years) can be counted on the fingers of one ear.

 You may call it multiplication work[ing] as expected when the product of two
 positive numbers comes out negative; I call it a wrong answer.

 Prelude let tens = 1 : map (*10) tens :: [Int]
 Prelude take 19 tens
 [1,10,100,1000,1,10,
100,1000,1,
10,100,
1000,1,10,100,
1000,1,10,100]
 Prelude [x * x | x - take 19 tens]
 [1,100,1,100,1,100,
1,100,1,100,
7766279631452241920,1864712049423024128,2003764205206896640,
-2537764290115403776,4477988020393345024,5076944270305263616,
-8814407033341083648,4003012203950112768,-5527149226598858752]

 Yes, I know that Haskell has Integer.
 If I want to do more arithmetic than a bit of simple counting,
 I like to use it.
 The gibberish that Int multiplication spewed out above is why.

 Roughly speaking, there are three ways to handle integer
 arithmetic: the Lisp way, the Ada way, and the Java way.
 Lisp just gets it right (think Haskell's Integer type).
 Java *defines* wrong answers to be right.
 Ada recognises that sometimes you want modular arithmetic (so it offers you
 modular types) and sometimes you don't (so it offers you bounded but
 non-modular types, where overflow is trapped).

This issue is really a specific instance of the question:
Are computers finite or infinite?

If one says finite then the infinite-taped Turing machine has nothing
to do with computers
If one says infinite then the abstraction we are talking of is
unrelated to the boxes on our desks/palmtops.

If one recognises that in juggling between these two views -- dare I
say a central project for a programmer?? -- we need to stuff an
infinite conceptual object into a finite actual one.  And in doing so
some corners will be cut willy-nilly.

So to say Lisp is 'right' because arithmetic does not overflow at
machine word size limits misses the fact that it overflows more
unpredictably when the machine memory fills out. Lets look at good ol
factorial

fact 0 = 1
fact n = n * fact (n-1)

Now I ran it as fact 100 with signature Int - Int and with
Integer - Integer

In the first case I got 0 in about 3 seconds
In the second... I thought I'd see what happens but after about 2
minutes of the CPU fans maxing out, firefox started giving me alarms
about an 'unresponsive script'; I felt my machine had had enough
punishment and gave in with C-c!

And if that sounds like a unreal argument, consider representing and
storing Graham's number.

Of course I am arguing philosophically not pragmatically.
Philosophically: Graham's number is 'just' a finite number, though a
rather obese one
Pragmatically: 32-bits is unwise for a bank-balance, 64 should be a
bit more safe

So coming to the pragmatic and to lisp...
I remember a story (maybe apocryphal) about a robot in the MIT(?) lab
that did a lot of clever things and then tumbled down the stairs. When
asked, the concerned researcher/academic shrugged it off: It was
garbage collecting

If the robot had been programmed in C its real-time behavior would
have been sturdier though its integer overflow properties would have
been flimsier.

More pragmatically, its good to remember 

Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-20 Thread Ketil Malde

Richard A. O'Keefe o...@cs.otago.ac.nz writes:

 I think a better argument for twos complement is that you're just
 doing all of your computations modulo 2^n (where n is 32 or 64 or
 whatever), and addition and multiplication work as expected modulo
 anything.

 To me, that's not a better argument.  It isn't even a _good_ argument.
 It amounts to saying if you do things wrong, you can justify it by
 saying you're really doing something else right, and it's the programmer's
 fault for wanting the wrong thing.

Not only that, but in Haskell, you don't really know 'n', it is only
specified to be at least 23, or something like that.  Which basically
means that any code that relies on this behaviour without rigorously
checking it basically is wrong.

-k
-- 
If I haven't seen further, it is by standing in the footprints of giants

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-20 Thread Richard A. O'Keefe

On 20/08/2013, at 6:44 PM, Kyle Miller wrote:
 By working as expected I actually just meant that they distribute (as in 
 a(b+c)=ab+ac) and commute (ab=ba and a+b=b+a),

That is a tiny fraction of working as expected.
The whole modular arithmetic argument would come close to
having some virtue, *except* that division just plain does not
fit.  In particular, it's painfully easy to find x y such that
 (x*y) div y is not congruent to x modulo 2**n.

The existence of division makes the everything's OK because
it's modular argument look very sick indeed.

  The interpretation of any of these numbers being positive or negative is 
 specious, but people still do it because it works reasonably well for small 
 integers.

No, they do it because their programming language specifications
encourage them to do it, because their introductory courses teach
them to do it, and their compilers, on seeing x  0, do not scream
at them that is not well defined!, so the idea that it is
supposed to work is constantly reinforced.  And above all, people
still do it because in most programming languages they have no
practical alternative.

  Also, there's the definite advantage that you can use the same instructions 
 for adding/multiplying signed and unsigned integers (for instance, pointer 
 arithmetic).

As the user of a programming language, what conceivable advantage
is that to me?  All the machines I have access to these days have
two sets of multiply and divide instructions, and there have been
machines with two sets of add and subtract instructions, and it is
no big deal.

The B6700 had one set of instructions (which actually dealt with both
integers and floating point).  It didn't have _any_ instructions for
unsigned integer arithmetic, and Fortran, COBOL, BASIC, Pascal, Algol,
and PL/I programmers didn't miss them.  (In particular, to a B6700
programmer familiar with his/her machine's instruction set, the idea
that variable access might have anything to do with unsigned
operations would have seemed, heck, did seem quite bizarre.)

For that matter, IBM mainframes have had, since the 1960s,
A   signed Add
AL  unsigned Add Logical
S   signed Subtract
SL  unsigned Subtract Logical
M   signed Multiply \ 
ML  unsigned Multiply Logical   | these four
D   signed Divide   | are common
DL  unsigned Divide Logical /
and it never stopped them being fast.  I doubt that the presence of
these instructions had any significant effect on the complexity of
the machines.  Even some 1980s single-chip machines did this.

 You mention that the B6700 trapped on overflows.  While this is a nice 
 feature, this has nothing to do with the number format.

That's half true.  The B6700 number format was such that there was nothing
sensible they _could_ do on integer overflow.  (Look it up or trust me;
truncation would have been violently unnatural on those lovely machines.)

 One example of a nice thing about doing computations modulo 2^n is that you 
 can do a bit twiddling trick called reciprocal multiplication (maybe 
 sometimes called magic number multiplication).  One reference for this is at 
 [1].  Another reference is Hacker's Delight.  But maybe you can save this for 
 your ear's fingers.

I have a copy of Hacker's Delight within arm's reach.
This is not really something that people writing applications want.
Usually, what they need is affordable multiplication and division
that give right answers when right answers are to be had and don't
drive the program insane with rubbish when right answers are not to
be had.

There are plenty of clever things computer architects can do, up to
and including keeping a last divisor cache in the division unit
to accelerate divisions that reuse a recent divisor.

 I can't really say I understand why anyone would actually want to use Int 
 (unless they knew they wanted a modulo 2^n Int).

Because they are calling an existing function that requires it.

It's just like the question the only integral type in standard C that
*cannot* be used safely to hold an 8-bit character is char, so why
would anyone want to use char*?  Answer: because of all the library
functions that demand it.

 but Integer is actually (if you're using GMP with your ghc):

Yes, that's tolerably well known.  You only pay the space overhead
when you need it (like Lisp or Smalltalk).  But you always pay the
time overhead.

 Where are you getting that about C?  Do you mean that it's careful to allow 
 implementations to decide to trap overflows?  Because as far as I can tell, 
 the C standard just says signed overflows give undefined behavior.

The thing is that the standardisers *could* have defined signed int arithmetic
to wrap (just like the benighted Java designers did) but they *chose* to leave
the effect undefined (just like the Pascal standard) *so that* implementations
that trap on overflow (which 

Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-19 Thread Kyle Miller
On Sun, Aug 18, 2013 at 8:04 PM, Richard A. O'Keefe o...@cs.otago.ac.nzwrote:

 The argument for twos-complement, which always puzzled me, is that the
 other
 systems have two ways to represent zero.  I never found this to be a
 problem,
 not even for bitwise operations, on the B6700.  I *did* find abs x  0
 succeeding to be a pain in the posterior.  (The B6700 had two different
 tests:
 'are these two numbers equal' and 'are these two bit patterns equal'.)


I think a better argument for twos complement is that you're just doing all
of your computations modulo 2^n (where n is 32 or 64 or whatever), and
addition and multiplication work as expected modulo anything.  The idea of
negative and positive in a system like this is artificial, though.  The
standard convention follows from the observation that 0-1 should be -1, and
if you use the hardware that is for positive numbers, and assume that you
can always carry another 1 for the highest order bit, then 0-1 is
...111.  It's not that 2^n - 1 is actually -1, but that it acts like a
-1 would act.  It's only by convention that numbers which begin with a 1
are considered to be negative (that, and Intel has special hardware for
detecting if a number has its leading 1 set).

However, we could adopt the convention that you need two leading ones to
make a negative number, and everything would work out, except for the
inequality testing built into the CPU.  This would give us a lot more
positive numbers, and then abs wouldn't have this problem :-)

Or, three other options: 1) make MIN_INT outside the domain of abs, 2) make
the range of abs be some unsigned int type, or 3) use Integer (i.e., use a
type which actually represents integers rather than a type which can only
handle small integers).

Kyle
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-19 Thread Brandon Allbery
On Mon, Aug 19, 2013 at 11:43 AM, Kyle Miller kmill31...@gmail.com wrote:

 Or, three other options: 1) make MIN_INT outside the domain of abs, 2)
 make the range of abs be some unsigned int type, or 3) use Integer (i.e.,
 use a type which actually represents integers rather than a type which can
 only handle small integers).


I think I would just document that Int is intended to represent a machine
word and therefore inherits the behavior of machine words, behavior at its
extrema is subject to the CPU behavior as a result, and if consistent
behavior is required then Integer should be used. (Indeed, it should
probably note that Int is a performance hack; but then you run into all the
Data.List etc. functions that use it.)

-- 
brandon s allbery kf8nh   sine nomine associates
allber...@gmail.com  ballb...@sinenomine.net
unix, openafs, kerberos, infrastructure, xmonadhttp://sinenomine.net
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-19 Thread Richard A. O'Keefe

On 20/08/2013, at 3:43 AM, Kyle Miller wrote:

 On Sun, Aug 18, 2013 at 8:04 PM, Richard A. O'Keefe o...@cs.otago.ac.nz 
 wrote:
 The argument for twos-complement, which always puzzled me, is that the other
 systems have two ways to represent zero.  I never found this to be a problem,
 not even for bitwise operations, on the B6700.  I *did* find abs x  0
 succeeding to be a pain in the posterior.  (The B6700 had two different tests:
 'are these two numbers equal' and 'are these two bit patterns equal'.)
 
 I think a better argument for twos complement is that you're just doing all 
 of your computations modulo 2^n (where n is 32 or 64 or whatever), and 
 addition and multiplication work as expected modulo anything.

To me, that's not a better argument.  It isn't even a _good_ argument.
It amounts to saying if you do things wrong, you can justify it by
saying you're really doing something else right, and it's the programmer's
fault for wanting the wrong thing.

One great thing about the B6700 was that you were guaranteed
EITHER the mathematically correct answer in the numbers you were
thinking in terms of OR an exception telling you the machine couldn't
do what you wanted.  When it comes to *applications* programming,
the number of times I have *wanted* arithmetic modulo 2^n (in the last
40 years) can be counted on the fingers of one ear.

You may call it multiplication work[ing] as expected when the product of two
positive numbers comes out negative; I call it a wrong answer.

Prelude let tens = 1 : map (*10) tens :: [Int]
Prelude take 19 tens
[1,10,100,1000,1,10,100,1000,1,10,100,1000,1,10,100,1000,1,10,100]
Prelude [x * x | x - take 19 tens]
[1,100,1,100,1,100,1,100,1,100,7766279631452241920,1864712049423024128,2003764205206896640,-2537764290115403776,4477988020393345024,5076944270305263616,-8814407033341083648,4003012203950112768,-5527149226598858752]

Yes, I know that Haskell has Integer.
If I want to do more arithmetic than a bit of simple counting,
I like to use it.
The gibberish that Int multiplication spewed out above is why.

Roughly speaking, there are three ways to handle integer
arithmetic: the Lisp way, the Ada way, and the Java way.
Lisp just gets it right (think Haskell's Integer type).
Java *defines* wrong answers to be right.
Ada recognises that sometimes you want modular arithmetic (so it offers you
modular types) and sometimes you don't (so it offers you bounded but
non-modular types, where overflow is trapped).

Even the C standard is careful to allow signed arithmetic to trap overflows.

When we tell our students that there is an integer N  0 such that N+1  0,
first they are shocked and confused, then they forget about it, and then
they are caught by it, and at last they remember it, but aren't sure what
they can _do_ about it in Java.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-18 Thread Nicolas Frisby
The docs at


http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:gcd

give a NB mentioning that (abs minBound == minBound) is possible for
fixed-width types.

This holds, for example, at Int. It is also the case that (negate minBound
== minBound).

Two questions:

  1) This behavior surprised me. Does it surprise enough people to include
a warning in the Haddock for abs and negate? IE Here.


http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Num

  2) Is this a common behavior in other languages? My tinkering with gcc
suggests it does not support the value -2^63, but instead bottoms out at
(-2^63+1).

Thanks.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] abs minBound (0 :: Int) negate minBound == (minBound :: Int)

2013-08-18 Thread Richard A. O'Keefe

On 19/08/2013, at 3:38 AM, Nicolas Frisby wrote:

 The docs at
 
   
 http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:gcd
 
 give a NB mentioning that (abs minBound == minBound) is possible for 
 fixed-width types.

At least three ways to represent negative integers in binary have been used:
- twos-complement   (asymmetric, -INT_MIN == INT_MIN, abs can have a negative 
result)
- ones-complement(symmetric, -INT_MIN == INT_MAX, abs is always 
non-negative)
- sign-and-magnitude (symmetric, -INT_MIN == INT_MAX, abs is always 
non-negative)

Having used a B6700 as an undergraduate, I still think sign-and-magnitude is the
only really safe-and-simple scheme.  However, twos-complement has conquered.

The argument for twos-complement, which always puzzled me, is that the other
systems have two ways to represent zero.  I never found this to be a problem,
not even for bitwise operations, on the B6700.  I *did* find abs x  0
succeeding to be a pain in the posterior.  (The B6700 had two different tests:
'are these two numbers equal' and 'are these two bit patterns equal'.)

 Two questions:
 
   1) This behavior surprised me. Does it surprise enough people to include a 
 warning in the Haddock for abs and negate?

We cannot expect everyone who uses Haskell to be familiar with
the eccentricities of popular hardware.  I think it's worth mentioning.

   2) Is this a common behavior in other languages?

Yes.

 My tinkering with gcc suggests it does not support the value -2^63, but 
 instead bottoms out at (-2^63+1).

Your tinkering was insufficient.

f% cat 2c.c
#include stdio.h
#include limits.h

int main(void) {
printf(%d\n, INT_MIN + INT_MAX);
return 0;
}
f% gcc 2c.c
f% a.out
-1

Oh wait.  You said 63, not 31.

Change the key line to

printf(%lld\n, LLONG_MIN + LLONG_MAX);

LLONG_MIN is going to be -(2**63) on any SPARC, x86, x86-64,
Power(PC), Alpha, ARM, MIPS, or z/Series machine, and a host
of others.

 
 Thanks.
 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe