Error in rounding off values using .round in Ruby - ruby

The following piece of code works perfectly in script/console but returns the following error when i compile the same in a ruby script.:
:in `round': wrong number of arguments (1 for 0) (ArgumentError)
tf={"ph"=>{0=>1.33333333333333, 1=>1.5}, "fee"=>{0=>1.66666666666667}, "test"=>{0=>1.16666666666667, 1=>1.25}, "what"=>{0=>2.0, 1=>2.0}, "for"=>{0=>1.5}, "is"=>{0=>1.83333333333333, 1=>1.75}}
tf.each{|k,v| v.each{|k1,v1| tf[k][k1]=(v1.round(5))}}
Any Ideas ? Cheers !

Float#round seems to work differently in Ruby 1.8 and Ruby 1.9: in 1.8 it complains about the given argument, in 1.9 returns back float properly rounded to the given number of decimals.
But, as the article linked in the other answer wisely says:
you should consider the reason you’re
performing the rounding (or
equivalent) operation. If it’s for
presentation reasons only a better way
might be to use a format string
instead, and leave the original data
intact.

From what it looks like, you are not supposed to pass an argument to the round method. You have passed 5 to it.
If you are trying to round it to 5 decimal places, there is no builtin method for that (that I'm aware of). This is a page that explains how to do so: http://solutions.hans-eric.com/rounding-off-floating-point-numbers-in-ruby

Related

ArgumentError when upgrading from Ruby 2.7 to 3.0 - related to separation of positional and keyword arguments?

I am trying to upgrade gems from ruby 2.7.0 to 3.0.0. I have tried to read and plan ahead for what roadblocks I'd hit, like the Separation of positional and keyword arguments.
I have updated two gems smoothly, but I have started to upgrade a third and, while testing the 3.0 update with RSpec, have run into the following error:
ArgumentError:
wrong number of arguments (given 1, expected 0; required keyword: children)
I am trying it instantiate a Class through a Factory. The stack trace is pointing back to the arguments of this function:
# rubocop:disable Style/KeywordParametersOrder
def initialize(parent_obj: nil, children:, **attributes)
#attributes = attributes
#parent = parent_obj
#children_json = children
end
# rubocop:enable Style/KeywordParametersOrder
Though I don't think it is significant, I have included the rubocop dis/enable lines just in case they are important.
The Factory is calling the class in this fashion:
data = {:some_data=>"foo", :some_name=>"bar", :children=>[]}
Long::Class::Name.new(data)
Now, when I pry into the code between data and Long::Class::Name.new(data) and instantiate my own Long::Class::Name like below:
Long::Class::Name.new(children: children, attributes: data)
it results in a successful creation without the ArgumentError.
I think to myself, "Cool, I'll just update the Factory's Class call to this new format and re-run the tests." After doing this, I am still getting the same ArgumentError as above.
I believe this is an issue with positional/keyword arguments like I linked above, but I am having trouble seeing how I can correct this. Besides the link above, I have also looked into Ruby 3 Keyword Arguments, as well as Hash and Keyword Coercion and Ruby 3 Changes. I believe I am facing the "Unforeseen Consequences" portion of that last link.
I have also looked at this Stack Overflow issue about ArgumentError after updating from Ruby 2.7 to Ruby 3.0 and tried to understand how I could use the first portion of the first answer to help me with my issue (disregarding the Update related to a PR).
Any thoughts on how can I dispel or work around this error? I have many gems I need to update and I am sure this will not be the last time I see this error. Any help would be greatly appreciated. Let me know if more information is needed.
When you do this…
data = {:some_data=>"foo", :some_name=>"bar", :children=>[]}
Long::Class::Name.new(data)
…you are calling the method with one positional argument (a hash containing the keys :some_data, :some_name, and :children) and no keyword argument.
If you instead were to call it like this…
Long::Class::Name.new(**data)
…you would be calling it with no positional argument and three keyword arguments.
This is called the "double splat" and was introduced for exactly your usecase, turning a hash into keyword arguments.

String include weird behavior

I was doing a code golf (use the minimum number of characters) and I had the following working Python solution. I was trying to shorten my code by re-writing it to Ruby but my Ruby code would always print false.
The code had to read two strings, to ignore the case and to tell whether it was possible to obtain one string by rotating the other string. The output had to be either true or false. Do you have any idea what I did wrong in Ruby?
Python 3 (64 characters) - Works
a=input().lower()
b=input().lower()
print(str(a in 2*b).lower())
Ruby (47 characters) - Always prints "false"
a=gets.upcase
b=gets.upcase
p (b*2).include? a
With the examples I can think of, the Ruby code works correctly, but for some reason, it didn't work on the code golf site (codingame.com, the problem was proposed by user "10100111001").
In Ruby gets includes the \n at the end. You'd have to .chomp it away before doing anything.
a=gets.chomp.upcase
b=gets.chomp.upcase
p (b*2).include? a
By the way, this is not the right way to "tell whether it was possible to obtain one string by rotating the other string", it only partially solves the problem, hope you know that.

Ruby: difference between hexencode and hexdigest

Today I read the documentation on Rubies hexdigest method, e.g.
Digest::SHA256.hexdigest('123')
=> "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"
The documentation says:
Returns the hex-encoded hash value of a given string. This is almost equivalent to Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
Highlighting is by me: What does almost mean here? How is it different?
Of course my example string above yields the same result:
Digest.hexencode(Digest::SHA256.digest('123'))
=> "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"
Can anyone point me to the cases where the result can be different? I want to understand whether the "almost" points to an important difference or if the difference is irrelevant for me.
As in the module Digest::Instance described hexdigest(string) return hexencode_str_new(value);. In the module Digest described hexencode(string) return hexencode_str_new(value); too. So, there are no differences if use same instance type. "almost" because in the documentation example can be Digest::SHA512 or other.

Comparing two virtually identical BigDecimal numbers in Ruby on Rails

I got a little problem that I really would like to understand. I am using assert_equal to compare two BigDecimal numbers that are supposed to be identical. They actually are except a very little tiny fraction, see below:
-#<BigDecimal:7f4b40e8de78,'0.4021666666 6666666666 666666667E2',36(45)>
+#<BigDecimal:7f4b40e85db8,'0.4021666666 6666666666 6666668E2',36(63)>
I use assert_in_delta in order to not fail the test cases. So I got a reasonable workaround. I do wonder though whether it would be possible to have it equal:
assert_equal (241.30.to_d/6), model.division_function
The model's division_function does exactly the same. It divides a BigDecimal of value 241.3 by the length of an array, which is 6.
There seems to be a very tiny difference in the precision.
I would like to know where that might come from?
Is there a way I can control precision more accurately?
EDIT
I am using Mongoid. It is worth to note that Mongoid offers BigDecimal as a field type, but it is stored as a string. However, I don't think this is the problem. I believe it is a Ruby thing.
EDIT
I got a little further with an example which hints that it is a Ruby issue and not directly related to Rails. Please see below:
irb(main):041:0* amount1 = BigDecimal("241.3")
=> #<BigDecimal:7f49bcb03558,'0.2413E3',18(18)>
irb(main):042:0> amount2 = BigDecimal("1800")
=> #<BigDecimal:7f49bcaf3400,'0.18E4',9(18)>
irb(main):043:0> rate = amount1 / amount2
=> #<BigDecimal:7f49bcae8398,'0.1340555555 5555555555 5555556E0',27(45)>
irb(main):044:0> rate * amount2 #should return amount1 = 241.3, but it does not :-(
=> #<BigDecimal:7f49bcad6a30,'0.2413000000 0000000000 00000008E3',36(45)>
irb(main):045:0>
I reported the bug to the Ruby core team. However, this is not a bug as you can see in the rejection response.
BigDecimal, though offers arbitrary precision, cannot represent numbers like 1/3 precisely. Thus during some arithmetic you can encounter imprecisions.
You can use Rational in Ruby for exact numbers. Exercise caution when doing arithmetics if you wish to keep the result exact.

Is it possible to redefine 0 in ruby?

I'm not actually going to use this in anything in case it does actually work but is it possible to redefine 0 to act as 1 in Ruby and 1 to act as 0? Where does FixNum actually hold its value?
No, I don't think so. I'd be very suprised if you managed to. If you start overriding Fixnum's methods/operators, you maaaybe might get near that (i.e. override + so that 1+5 => 5, 0+5 => 6 etc), but you will not get full replacement of literal '0' with value 1. At least marshalling to native would expose the real 0 value of the Fixnum(0).
To be honest, I'm not really sure if you can even override the core operations like + op on a Fixnum. That could break so many things..
As far as I remember from 1.8.3 source, simple integers and doubles are held right inside a 'value' and are copied all around *). There is no singular "0", "1" or "1000" value. There is no extra dereference that would allow you to swap all the values with one shot. I doubt it changed in 1.9 and I doubt anyone got any weird idea about that in 2.0. But I don't actually know. Still, that would be strange. No platform I know interns integers and floatings.. Strings, sometimes array literals, but numbers?
So, sorry, no #define true false jokes :)
--
*) clarification from Jörg W Mittag (thanks, this is exactly what I was referring to):
(..) Fixnums do not have a place in memory, their pointer value is "magic" (in that it cannot possibly occur in a Ruby program) and treated specially by the runtime system. Read up on "tagged pointer representation", e.g. here.
Assignment does not alias Fixnum objects. There is effectively only one Fixnum object instance for any given integer value, so, for example, you cannot add a singleton method to a Fixnum. Any attempt to add a singleton method to a Fixnum object will raise a TypeError. Source
That pretty much means you can't edit a Fixnum and therefor not redefine 0 or 1 in native ruby.
Though as these Fixnums are also Objects they have unique object id's that cleary reference them somewhere in the memory. See BasicObject#__id__
If you can locate the memory space where 0 and 1 objects are and switch these, you should have effectivle switched 0 and 1 behavior in ruby as now either will reference the other object.
So to answer your question: No redefining Fixnums is not possible in Ruby, switching their behaviour should be possible though.

Resources