Date Increment Issue - ruby

-> irb
>> (Date.today +3).to_s
=> "2009-10-22"
>> (Date.today + 3).to_s
=> "2009-10-25"
between "+3" and "+ 3", there is a difference?

"+3" with no space means positive 3, which gets passed to the today method as an argument, while "+ 3" means plus three, so the return value of the today method gets added to 3.
In case you're curious, the optional parameter to the today method "specifies the Day of Calendar Reform", for conversions to other date formats.

I realize this must have been a frustrating bug to discover. When using a language where method invocation has optional parentheses, whitespace is a delicate matter. Consider the following:
square(2+2)*2 # square(4)*2 = 16*2 = 32
square (2+2)*2 # square(4*2) = square(8) = 64
Your case is trickier because the +3 with no space is actually a unary operator. ! ~ and + unary operators have the highest precedence.
Also interesting the - unary operator has a lower precedence than the exponentiation operator. Therefor
-4**2 # -(4**2) = -16

It seems to me that the + binds to the 3 in the first case. That is the interpreter sees Date.today(+3). If there's a space after the plus the interpreter instead sees (Date.today) + (3).
Using + to denote positive numbers isn't very common since numbers are positive to begin with, but consider the case of negative numbers: it's easier to see that Date.today -3 means something else than Date.today - 3.

Related

Numbers vs string/expressions vs values

When I type the following:
print "2+2 is equal to" +2+2
I get an error message saying I can't convert a number into a string, but when I type:
print "2+2 is equal to", 2+2
it's accepting it and displays:
2+2 is equal to4
What's the difference between the two? It's not making logical sense to me. Could someone please explain it?
print "2+2 is equal to" + 2 + 2
Here you're trying to add a number to a string. This operation doesn't make sense. It's like adding an apple to a cat. The addition fails, but if it were to succeed, then print would print the result.
print "2+2 is equal to", 2 + 2
Here you're telling the print command to print this string and also result of summing these two numbers. it knows how to print strings and how to print numbers. Strings and numbers don't have to be mixed together in this case, they are handled separately. That's why this operation succeeds.
You can make the first operation work too. For this, you must be explicit that you want this number as a string, so that both addition operands are strings and can be actually added together.
print "2+2 is equal to" + (2 + 2).to_s
or
print "2+2 is equal to #{2 + 2}" # this is called string interpolation
Some languages try to be friendly and, if you're adding a number to a string, will stringify the number for you. Results can be... surprising.
Javascript:
"2 + 2 equals to " + 2 + 2
# => "2 + 2 equals to 22"
"2 + 2 equals to " + (2 + 2)
# => "2 + 2 equals to 4"
It's good that ruby doesn't do this kind of tricks :)
Everybody's pointed out how print works, so i thought i'd shed a bit of light on +.
These two operators look the same, right?
'2'+'2'
2+2
In actual fact, there are two very different operations happening:
String#+ - This concatenates the argument to the source string. Argument must be a string.
Fixnum#+ - This adds the argument to the source number. Argument must be a number.
So if String#+ only works on string objects, how is it that we can print different types of objects?
Some classes are very 'string-like' and can be treated as strings in most contexts (eg. Exception before Ruby 1.9) as they implement to_str(implicit conversion).
We can also implement to_s in our own objects to allow it to return a String representation of the object (explicit conversion).
You can read more about this at http://codeloveandboards.com/blog/2014/03/18/explicit-vs-implicit-conversion-methods/
print "2+2 is equal to" +2+2
is equivalent to:
print("2+2 is equal to" +2+2)
You are trying to add an integer 2 to a string "2+2 is equal to".
print "2+2 is equal to", 2+2
is equivalent to:
print("2+2 is equal to", 2+2)
Here print takes two arguemnts, one is a string, the other is an expression 2+2.
print "2+2 is equal to" + 2+2
fails because it tries to add a integer to a string before the result is send to print. An operation that does not make sense. Whereas:
print "2+2 is equal to", 2+2
is a other operation. Here you send two argument to print. A string and an integer. Internally print calls to_s on both values.
From the documentation:
print(obj, ...) → nil
Prints each object in turn to $stdout. [...] Objects that aren't strings will be converted by calling their to_s method.
Another way to do this is string interpolation, that also calls to_s automatically:
print "2+2 is equal to #{2+2}"

sorted array with Number shuffle

i am working on the problem of Number shuffle https://rubymonk.com/learning/books/1-ruby-primer/problems/154-permutations#solution4802. exercises asks to:
return a sorted array of all the unique numbers that can be formed
with 3 or 4 digits.
there is a solution (See the Solution) below the exercise, that looks like this:
def number_shuffle(number)
no_of_combinations = number.to_s.size == 3 ? 6 : 24
digits = number.to_s.split(//)
combinations = []
combinations << digits.shuffle.join.to_i while
combinations.uniq.size!=no_of_combinations
combinations.uniq.sort
end
I have a few questions, can anyone explain me:
1) in 'no_of_combinations' variable what does it mean '3 ? 6 : 24'? i think 3 is amount of digits in the number. question mark ( ? ) is symbol of 'if'- if number digits are 3, the amount of numbers will be 6 in the array of combinations. colon (punctuation) is symbol sign, but i do not know why 24, there are 23 symbols considering white space in the array of combinations.
2) what does it mean << symbol after combinations? i know that it is addition sign, but what does it do here? and also, what it means exclamation mark after 'size' in the following string?
1) in 'no_of_combinations' variable what does it mean '3 ? 6 : 24'?
The expression needs to include the comparison to make sense . . .
number.to_s.size == 3 ? 6 : 24
This is the ternary if. If the comparison before the ? is true, it evaluates to the first value (6 here), if it is false it evaluates to the second value (24 here). It has nothing to do with literal Symbol values . . . in fact Ruby parser will always treat the colon as a value separator here, however you space it.
The syntax of this operator is originally from C, and you will find it copied to many other languages.
2) what does it mean << symbol after combinations? i know that it is addition sign, but what does it do here?
It is not an addition sign. This operator does different things depending on the class of the object (on the left). In this example, that is an Array, and << pushes the object on the right onto the end of the array. It is almost identical to push
and also, what it means exclamation mark after 'size' in the following string?
In this case it is part of !=, or "not equals" comparison operator. The original author could have made this clearer with a bit of whitespace.

Write Multiline Arithmetic in Ruby

How to write multiline arithmetic properly in Ruby? Previously, i have tried something like y, then i realized there is something wrong with that code. I need to write multiline arithmetic due to my very long equation.
a = 5
b = 5
x = (a + b) / 2
puts x # 5, as expected
y = (
a
+ b
) /
2
puts y # 2, what happened?
The Ruby parser will assume a statement has ended if it looks like it has ended at an end of the line.
What you can to do prevent that is to leave the arithmetic operator just before a new line, like this:
a = 1
b = 2
c = a +
b
And you'll get the result you expect.
(
expr1
expr2
)
is actually, in Ruby, the same as
(expr1; expr2)
which just executes the first expression (for side effects) and returns the second one (also after evaluating it)
Try thinking about the "expectations" of the interpreter, and remember that in ruby EVERYTHING is an expression (which means that everything evaluates to some value, even constructs that in other languages are considered "special", like if-then-elses, loops, etcettera).
So:
y = ( #1
a #2
+ b #3
) / #4
2 #5
At line 1 we start the declaration of a variable, and the line ends with an open (pending) parenthesis. The interpreter expects the rest of the definition, so it proceeds to the next line looking for a VALUE to assign to the var y.
At line 2, the interpreter finds the variable a, but no enclosing parenthesis. It evaluates a, which has value 5, and since the line 2 is a perfectly-valid expression, the interpreter understands that this expression is finished (since in Ruby a newline OFTEN means end-of-expression indicator).
So up to now it has produced a value 5, but the only expectation it still has is that it must match the enclosing parenthesis.
If after that the interpreter had found the enclosing parenthesis, it would have assigned the value of a (i.e. 5) to the parenthesis expression (because everything must have a value, and the last value produced will be used).
When the interpreter reaches line 3, it finds another perfectly-valid ruby expression, + b. Since + 5 (5 being the value of variable b) is a VALID integer declaration in ruby, the interpreter sees it as standalone, not at all related to the previous 5 evaluated for the variable a (remember, it had no other expectation, except the one for the parenthesis).
In short, it throws away the value obtained for a, and uses only the value obtained with + b. In the next line it finds the enclosing parenthesis, and so the parenthesis-expression gets assigned the last produced value, which is a 5 produced by the expression + b.
Since on line 4 the interpreter finds a /, it (correctly) understands it as the division method of an integer, since it has produced an integer up to now (the int 5)! This creates the expectation for possible arguments of the method, which it finds on line 5. The resulting evaluated expression is y = 5 / 2, which equals 2 in integer division. So, basicaly, here is what the interpreter did:
y = ( # Ok, i'm waiting for the rest of the parenthesis expression
a # cool, a has value 5, if the parenthesis ends here, this is the value of the expr.
+ b # Oh, but now I found + b, which has value + 5, which evaluates to 5. So now this is the last value I have evaluated.
) / # Ok, the parenthesis have been closed, and the last value I had was a 5. Uow, wait, there is a slash / there! I should now wait for another argument for the / method of the 5 I have!
2 # Found, let's make y = 5 / 2 = 2!
The problem here is that on line #2, you should have left an expectation for the interpreter (exactly as you left on line 4 with the / method), which you did not!
The answer of #Maurício Linhares suggests exactly this:
y = (
a +
b
) /
2
By moving the + method to the end of the line 2, you tell the interpreter that your expression is still not complete! So it keeps the expectation and proceeds to line #3 to find the right operand of the expression (or, more precisely in Ruby, an argument for the + method :D).
The same works with string concatenation:
# WRONG, SINCE + "somestring" is not a valid stand-alone expression in ruby
str = "I like to"
+ " move it!"
# NoMethodError: undefined method `+#' for " move it!":String
# CORRECT, by leaving the + sign as last statement of the first line, you
# keep the 'expectation' of the interpreter for the next
# argument of the + method of the string object "I like to"
str = "I like to" +
" move it!"
# => "I like to move it!"
The difference is that in your code there were no error thrown, since + b is actually a valid expression.
I hope my answer was useful on giving you some intuition on WHY it was not working as expected, sorry if I'm not concise :)

Ruby operator "+" behavior varies depending on spacing in code?

I came across a bit of an oddity (am using Ruby 1.9.1). Case scenario being:
class D
...
def self.d6
1+rand(6)
end
...
end
v = D::d6+2 # fine and dandy
v = D::d6 +2 # in `d6': wrong number of arguments (1 for 0) (ArgumentError)
v = D::d6 + 2 # fine and dandy
Why the "+2" in second case is treated as being "positive 2" and not an "addition of 2"?
The + same as the - in ruby are overloaded in order to make the syntax look nice.
When there is no space the Ruby parser recognizes the + as the method which is called on the result of d6 which is an Integer.
Same goes for the version with space before and after the +.
However: In the operator precedence in Ruby + as a unary operator is defined before + as a binary operator (as is often the case in other languages as well).
Therefore if there is a space before the + but not after it, the Ruby Parser will recognize it as d6(+2) which fits the error message.

Force Ruby to not output a float in standard form / scientific notation / exponential notation

I have the same problem as is found here for python, but for ruby.
I need to output a small number like this: 0.00001, not 1e-5.
For more information about my particular problem, I am outputting to a file using f.write("My number: " + small_number.to_s + "\n")
For my problem, accuracy isn't that big of an issue, so just doing an if statement to check if small_number < 1e-5 and then printing 0 is okay, it just doesn't seem as elegant as it should be.
So what is the more general way to do this?
f.printf "My number: %.5f\n", small_number
You can replace .5 (5 digits to the right of the decimal) with any particular formatting size you like, e.g., %8.3f would be total of 8 digits with three to the right of the decimal, much like C/C++ printf formatting strings.
If you always want 5 decimal places, you could use:
"%.5f" % small_number
I would do something like this so you can strip off trailing zero's:
puts ("%.15f" % small_number).sub(/0*$/,"")
Don't go too far past 15, or you will suffer from the imprecision of floating point numbers.
puts ("%.25f" % 0.01).sub(/0*$/,"")
0.0100000000000000002081668
This works also on integers, trim excess zeros, and always returns numbers as a valid floating point number. For clarity, this uses the sprintf instead of the more cryptic % operator.
def format_float(number)
sprintf('%.15f', number).sub(/0+$/, '').sub(/\.$/, '.0')
end
Examples:
format_float(1) => "1.0"
format_float(0.00000001) => "0.00000001"

Resources