Behaviour with `repeated_permutation` and floating points - ruby

I'm solving Project Euler problem 33.
(10..99).to_a.repeated_permutation(2) do |ary|
print (ary[0]/ary[1]).to_f if ary[0]/ary[1] < 1
end
returns nothing but a series of decimal places and zeros. However if I take the values of the array and divide them manually, for instance:
print 98/99.to_f
the correct value is returned.
Can anyone explain why this happens, and (more importantly) how to circumvent it?

Both ary[0] and ary[1] will always be positive integers inside your block. That means that ary[0]/ary[1] will be 0 or some positive integer. Your block does nothing when ary[0]/ary[1] is less than one (i.e. when ary[0]/ary[1] is anything other than zero). Since you only call print when ary[0]/ary[1] == 0, you're really just saying:
print 0.to_f if ary[0]/ary[1] == 0
This:
print 98/99.to_f
prints what you're expecting but you're not doing that in the block, you're saying things like:
print (98/99).to_f
and we see that the to_f call is in the wrong place.
You're probably trying to say:
print ary[0]/ary[1].to_f if ary[0]/ary[1] < 1
to get floating point division rather than integer division.

Related

Easy ROT13 Ruby "programme" mystery

I made a simple ROT13 programme and I don't understand one thing:
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
(a.length+1).times do |i|
print a[i + 13]
if i>13
print a[i %14]
end
end
Outputs:
NOPQRSTUVWXYZABCDEFGHIJKLM
If I don't add +1 after a.length, the iteration ends with the letter L. However, if I use print a[i] inside the iteration, it normally starts with A and ends with Z with no +1 addition needed.
Can someone explain this mystery for me?
I just needed a quick rot13 one liner and this SO entry was the first google result. I kept on searching and found a super small one by #xfaider that worked well enough for my purpose.
Just gonna post it here for the next person who wants a one-liner.
string.tr("A-Za-z", "N-ZA-Mn-za-m")
As you may know, the .times loop invokes the block specified number of times, passing into each iteration an incremented value.
If we say 26.times {|i| puts i} it will print values from 0 to 25. Up to, but not including the last value.
Now let's walk through the loop. At first iteration, i is 0. So we print 14th character of the string, "N" (at index 13, zero-based). We don't go into the condition because 0 is not greater than 13. On second iteration we print 15th character, "O". And keep doing this, until we reach i=14.
At this point, the "magic" begins. First, we attempt to print 27th character of the string. There's no such character so we print literally nothing. Then the condition is triggered and we go in.
i % 14 equals 0, so we print zeroth character, "A". Next iteration we print character at index 1 (15 % 14) and so on, until .times finishes its iteration and stops calling the block. Now, for this logic to work, the last value for i must be 26, so that we get 12 in i % 14 and print "M".
Length of the entire string is 26. Remember, .times counts up to but not including the number? That's why we add one to the length, so that it counts from 0 to 26. That's the mystery.
There are many-many ways of improving this code, and you'll learn about them in time. :)
Update
I knew something looked odd about the code. And, of course, there's a bug. When i is 13 we don't print the first time and we don't go into the condition. We waste one iteration. This is a classic example of "off by 1" class of errors. Here's fixed version of code that doesn't waste iterations and contains no mysteries:
a.length.times do |i|
print a[i + 13]
if i > 12
print a[i % 13]
end
end
The length of the string of letters is 26, however the index is 0 based. With this being the case, the letter Z is index number 25. The times method will not run the final iteration(26). Therefore to account for that, we add a +1 to the length.

Why is a 3rd variable necessary in this arithmetic progression sum’s code?

Why do I need a local variable result in this code? I guess I'm having an infinite loop when I try to use only 2 variables, but I don't get how to recognize this issue in the code and use debug to understand the issue.
# Write a method that takes in an integer num and returns the sum of
# all integers between zero and num, up to and including num.
def sum_nums(num)
result = 0
i = 0
while i <= num
result += i
i += 1
end
return result
end
So, in order for this code to work, you need to know three things: the number you are counting up to (num), the current value of the number (i), and the current sum from 0 to i. result is the variable keeping track of the sum from 0 to i.
However, this isn't a very ruby way of writing this method. while loops are meant to be used in situations where you don't know how many times you need to loop. In this case, you know the number of loops, so an iterator is better for this purpose.
def sum_nums(num)
(0..num).reduce(:+)
end
The above method will return the same result as your method.
In your function you use three variables:
num which holds the range over which you want to do the summing (or the number of times you need to loop)
i which holds the specific integer you are adding to the sum within each loop
result which holds the sum so far (and at the end of the final loop, holds the answer you want). Without this variable, the next loop would 'lose track' of how much all the previous loops had already added to the sum of integers.
You could get rid of the i variable as follows
result = 0
while num > 0
result += 1
num -= 1
end
return result
This relies on the fact that if you count down from num you know to stop at 0. Alternately you could get rid of both the i variable and the result variable as follows
return num*(num+1)/2
This relies on an algebraic formula for the sum of integers rather than explicitly carrying out the sum. Both of these snippets will produce the same return as your function.
In summary, you need the num variable, otherwise your function won't 'know' what range to do the sum over. You can get away without the i variable (but the meaning of the code may not be so obvious), but you can only get away without the result variable if you can find a method that doesn't need the loop.

Complex Numbers Seemingly Arising from Non-Complex Logarithms

I have a simple program written in TI-BASIC that converts from base 10 to base 2
0->B
1->E
Input "DEC:",D
Repeat D=0
int(round(log(D)/log(2),1))->E
round(E)->E
B+10^E->B
D-2^E->D
End
Disp B
This will sometimes return an the error 'ERR: DATA TYPE'. I checked, and this is because the variable D, will sometimes become a complex number. I am not sure how this happens.
This happens with seemingly random numbers, like 5891570. It happens with this number, but not something close to it like 5891590 Which is strange. It also happens with 1e30, But not 1e25. Another example is 1111111111111111, and not 1111111111111120.
I haven't tested this thoroughly, and don't see any pattern in these numbers. Any help would be appreciated.
The error happens because you round the logarithm to one decimal place before taking the integer part; therefore, if log(D)/log(2) is something like 8.99, you will round E up rather than down, and 2^9 will be subtracted from D instead of 2^8, causing, in the next iteration, D to become negative and its logarithm to be complex. Let's walk through your code when D is 511, which has base-2 logarithm 8.9971:
Repeat D=0 ;Executes first iteration without checking whether D=0
log(D)/log(2 ;8.9971
round(Ans,1 ;9.0
int(Ans ;9.0
round(Ans)->E ;E = 9.0
B+10^E->B ;B = 1 000 000 000
D-2^E->D ;D = 511-512 = -1
End ;loops again, since D≠0
---next iteration:----
log(D ;log(-1) = 1.364i; throws ERR:NONREAL ANS in Real mode
Rounding the logarithm any more severely than nine decimal places (nine digits is the default for round( without a "digits" argument) is completely unnecessary, as on my TI-84+ rounding errors do not accumulate: round(int(log(2^X-1)/log(2)) returns X-1 and round(int(log(2^X)/log(2)) returns X for all integer X≤28, which is high enough that precision would be lost anyway in other parts of the calculation.
To fix your code, simply round only once, and only to nine places. I've also removed the unnecessary double-initialization of E, removed your close-parens (it's still legal code!), and changed the Repeat (which always executes one loop before checking the condition D=0) to a While loop to prevent ERR:DOMAIN when the input is 0.
0->B
Input "DEC:",D
While D
int(round(log(D)/log(2->E
B+10^E->B
D-2^E->D
End
B ;on the last line, so it prints implicitly
Don't expect either your code or my fix to work correctly for D > 213 or so, because your calculator can only store 14 digits in its internal representation of any number. You'll lose the digits while you store the result into B!
Now for a trickier, optimized way of computing the binary representation (still only works for D < 213:
Input D
int(2fPart(D/2^cumSum(binomcdf(13,0
.1sum(Ans10^(cumSum(1 or Ans

Scope of variables and the digits function

My question is twofold:
1) As far as I understand, constructs like for loops introduce scope blocks, however I'm having some trouble with a variable that is define outside of said construct. The following code depicts an attempt to extract digits from a number and place them in an array.
n = 654068
l = length(n)
a = Int64[]
for i in 1:(l-1)
temp = n/10^(l-i)
if temp < 1 # ith digit is 0
a = push!(a,0)
else # ith digit is != 0
push!(a,floor(temp))
# update n
n = n - a[i]*10^(l-i)
end
end
# last digit
push!(a,n)
The code executes fine, but when I look at the a array I get this result
julia> a
0-element Array{Int64,1}
I thought that anything that goes on inside the for loop is invisible to the outside, unless I'm operating on variables defined outside the for loop. Moreover, I thought that by using the ! syntax I would operate directly on a, this does not seem to be the case. Would be grateful if anyone can explain to me how this works :)
2) Second question is about syntex used when explaining functions. There is apparently a function called digits that extracts digits from a number and puts them in an array, using the help function I get
julia> help(digits)
Base.digits(n[, base][, pad])
Returns an array of the digits of "n" in the given base,
optionally padded with zeros to a specified size. More significant
digits are at higher indexes, such that "n ==
sum([digits[k]*base^(k-1) for k=1:length(digits)])".
Can anyone explain to me how to interpret the information given about functions in Julia. How am I to interpret digits(n[, base][, pad])? How does one correctly call the digits function? I can't be like this: digits(40125[, 10])?
I'm unable to reproduce you result, running your code gives me
julia> a
1-element Array{Int64,1}:
654068
There's a few mistakes and inefficiencies in the code:
length(n) doesn't give the number of digits in n, but always returns 1 (currently, numbers are iterable, and return a sequence that only contain one number; itself). So the for loop is never run.
/ between integers does floating point division. For extracting digits, you´re better off with div(x,y), which does integer division.
There's no reason to write a = push!(a,x), since push! modifies a in place. So it will be equivalent to writing push!(a,x); a = a.
There's no reason to digits that are zero specially, they are handled just fine by the general case.
Your description of scoping in Julia seems to be correct, I think that it is the above which is giving you trouble.
You could use something like
n = 654068
a = Int64[]
while n != 0
push!(a, n % 10)
n = div(n, 10)
end
reverse!(a)
This loop extracts the digits in opposite order to avoid having to figure out the number of digits in advance, and uses the modulus operator % to extract the least significant digit. It then uses reverse! to get them in the order you wanted, which should be pretty efficient.
About the documentation for digits, [, base] just means that base is an optional parameter. The description should probably be digits(n[, base[, pad]]), since it's not possible to specify pad unless you specify base. Also note that digits will return the least significant digit first, what we get if we remove the reverse! from the code above.
Is this cheating?:
n = 654068
nstr = string(n)
a = map((x) -> x |> string |> int , collect(nstr))
outputs:
6-element Array{Int64,1}:
6
5
4
0
6
8

Defining "<" and ">" in Ruby

I am a freshman in high-school who has some time on his hands, and I decided it would be beneficial to write some programs that demonstrate what commonly used functions do. I have always wondered what exactly goes into the greater than and less than operators, so I have set out to define them by myself. The only roadblock that I have encountered is how one can assert that a value is negative or positive, without using the greater than or less than operators. So far, I have something that looks like this:
a = 34
b = 42
c = a - b
puts "A is Greater than B" while is_positive?(c)
Does anybody have ideas on how I would define is_positive?(c)?
This question should not be tagged ruby but mathematics.
Then you absolutely do need the equality operator.
If you want to restrict yourself to just the + and - operators, you have no other way of deciding whether a or b is greater, than to count up from 0 and see which value you hit first (which of course is tested using the equality operator)
You mean operator <=> that return -1 first argument is less, 0 if equal and 1 if greater than second? Or maybe you mean sign function that return -1 if argument is less than 0, 0 if is 0 or 1 if is greater than 0?

Resources