Bug #1708: require 'complex' Causes Unexpected Behaviour
http://redmine.ruby-lang.org/issues/show/1708
Author: Run Paint Run Run
Status: Open, Priority: Normal
Category: lib
ruby -v: ruby 1.9.2dev (2009-06-27 trunk 23871) [i686-linux]
1.9 has Complex in core, yet on 1.8 you had to explicitly require it
with "require 'complex'". However, 1.9 also has a 'complex.rb' in its
lib directory which in turn requires 'cmath.rb'. 'cmath.rb' redefines
quite a few Math methods. This is particularly confusing because you
would expect "require 'complex'" to be a no-op on 1.9, whereas it
actually causes Math methods to fail in mysterious ways.
For example, where Math used to raise TypeErrors it now raises
NoMethodErrors. This happens for all of the overridden methods.
>> Math.atan(nil)
TypeError: can't convert nil into Float
from (irb):1:in `atan'
from (irb):1
from /usr/local/bin/irb:12:in `<main>'
>> require 'complex'
=> true
>> Math.atan(nil)
NoMethodError: undefined method `real?' for nil:NilClass
from /usr/local/lib/ruby/1.9.1/cmath.rb:145:in `atan'
from (irb):3
from /usr/local/bin/irb:12:in `<main>'
As Complex is in core Math methods should work with complex numbers by
default. This half-in-, half-out-, approach is confusing. If the current
behavior is intentional, it needs to be clarified in the Math and
Complex documentation.
on 2009-06-30 21:40
on 2009-07-03 13:02
Issue #1708 has been updated by tadayoshi funaba. not a bug ---------------------------------------- http://redmine.ruby-lang.org/issues/show/1708
on 2009-07-03 18:18
Hi,
In message "Re: [ruby-core:24126] [Bug #1708] require 'complex' Causes
Unexpected Behaviour"
on Fri, 3 Jul 2009 20:01:54 +0900, tadayoshi funaba
<redmine@ruby-lang.org> writes:
|not a bug
Let me clarify. As Complex numbers made built-in in 1.9, Tadayoshi
asked me to make Math functions work well with complex numbers, but I
did want to keep semantics taken libm functions. So he separated
those functions into cmath.rb. And required it from complex.rb to
make 1.8 compatibility.
So options are:
* make those functions complex numbers aware from the beginning.
lose libm semantics and compatibility a bit.
* keep them as they are. they are at least compatible with 1.8.
* stop requiring cmath.rb from complex.rb. lose compatibility.
keep libm semantics.
* something else.
Opinion?
matz.
on 2009-07-03 19:11
Issue #1708 has been updated by Run Paint Run Run.
Thank you for the explanation, matz. :-)
When I heard that Complex had been moved to core I assumed that _all_
Complex functionality had been translated, include the Math extensions.
I imagine that this was a common reaction.
It would surely be optimal for the Math methods to seamlessly support
Complex numbers. Let's take Math.cos for example. Passing it a Complex
number without 'cmath':
>> Math.cos(Complex(1,2))
RangeError: can't convert 1+2i into Float
from (irb):79:in `to_f'
from (irb):79:in `cos'
from (irb):79
from /usr/local/bin/irb:12:in `<main>'
Passing it a Complex number with 'cmath':
>> Math.cos(Complex(1,2)).inspect
=> "(2.0327230070196656-3.0518977991517997i)"
In this case, what would be the harm of including 'cmath' by default?
Performance isn't affected for the common cases (non-Complex numbers),
yet Complex arguments "do the right thing". Indeed, the majority of the
methods in 'cmath' appear to be only act differently from the default if
their argument is Complex (and, in some cases, positive, too). What is
the benefit to the user of having a method raise an exception when it
could produce the right answer? Or, what do we lose by integrating
'cmath'?
Unless there are serious incompatibilities or performance concerns, it
seems more robust and well-rounded if Complex numbers work as one would
expect.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1708
on 2009-07-03 19:48
Hi,
In message "Re: [ruby-core:24129] [Bug #1708] require 'complex' Causes
Unexpected Behaviour"
on Sat, 4 Jul 2009 02:10:15 +0900, Run Paint Run Run
<redmine@ruby-lang.org> writes:
|When I heard that Complex had been moved to core I assumed that _all_ Complex functionality had been translated, include the Math extensions. I imagine that this was a common reaction.
According to the fail-early principle, unexpected situation should be
told (by raising an error) as early as possible. When the program do
not expect complex number calculation (or negative argument to sqrt),
it should cause an error, rather than continuing calculation with
complex numbers. Requiring 'complex' (or 'cmath') gives a chance to a
program to declare it is expecting complex number calculation.
Probably I think this way mostly because I have never had a chance to
use complex numbers excepct for testing the implementation. Those who
use complex numbers often might feel differently.
Of course I understand what you claim. It's a matter of trade-offs.
Tadayoshi would feel happy, I think, if you can persuade me.
matz.
on 2009-07-03 22:07
Issue #1708 has been updated by Run Paint Run Run. > According to the fail-early principle, unexpected situation should be > told (by raising an error) as early as possible. I'd always considered that to apply to calculations that would ultimately fail, the logic being that you should complain about arguments that would cause failure up front, rather than attempting to perform an expensive calculation with them and then failing. In this case, we don't need to fail. We can give the right answer. Let's use Math.sqrt(-2) for an example. Without 'cmath' the programmer's only option would be to rescue Errno::EDOM. With 'cmath' they could achieve the same effect by inspecting the result's #real? method, or they could perform mathematical operations on the result. With Complex implementing so many Numeric methods, it's perfectly possible for their code to continue to work with complex results. The difference being that now exceptions are much rarer. Integration of 'cmath' gives the programmer more control. Put another way, one can perform many more operations with a Complex object than he can with an Exception object. Further, Math.sqrt(-2) raising an exception seems dishonest. The answer is perfectly knowable and calculable; we'd raise an exception not because the input was exceptional but because, presumably, we wanted to protect the programmer from calling a method on the result that was allowed for reals, but disallowed for non-reals. That is, we'd want to protect the programmer from saying: Math.sqrt(n) > LIMIT # Raises a NoMethodError for :> if .sqrt returns a Complex Or: side = Math.sqrt(area_of_square) # .... cost = side * cost_per_side # cost may be a complex number... Note that a similar argument could be levied against methods that occasionally returned Floats, too. A programmer who blindly calls #odd? on the result will have the same shock as if he blindly called a Fixnum method on a result which was occasionally complex. Lastly, if we're considering programmers who may not expect to receive complex results from Math methods, we must also consider those who, knowing that Complex is in core, have the contrary expectation... ;-) And now I'll be quiet to give other parties a chance to participate. ;-) ---------------------------------------- http://redmine.ruby-lang.org/issues/show/1708
on 2009-07-04 05:57
Issue #1708 has been updated by tadayoshi funaba. ruby is a great believer in unix/c. Math.acosh(-1) # EDOM (-8) ** 0.5 #=> NaN 1 / 2 #=> 0 and require 'cmath' CMath.acosh(-1) #=> (0.0+3.141592653589793i) Complex(-8) ** 0.5 #=> (1.7318549141438708e-16+2.82842712474619i) Float(1) / 2 #=> 0.5 Rational(1) / 2 #=> (1/2) it's too hard. in scheme: (acosh -1) ;=> 0.0+3.141592653589793i (expt -8 0.5) ;=> 1.7318549141438708e-16+2.82842712474619i (/ 1 2) ;=> 1/2 it's so simple. i think that introducing complex number means extending the domain of ruby's numeric system. we should provide proper results in the domain. we should not restrict any general operations. we can always use "div" instead of "/" for integer division. and we can also provide FMath.sqrt as a restricted version, if you want. of course, this is an option. i'm looking forward to 2.0. ---------------------------------------- http://redmine.ruby-lang.org/issues/show/1708
on 2009-07-13 13:48
Issue #1708 has been updated by Yuki Sonoda. Status changed from Open to Rejected Assigned to set to tadayoshi funaba Was the issue rejected? right? ---------------------------------------- http://redmine.ruby-lang.org/issues/show/1708
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.