Ruby: Change negative number to positive number? - ruby

What's the simplest way of changing a negative number to positive with ruby?
ie. Change "-300" to "300"

Using abs will return the absolute value of a number
-300.abs # 300
300.abs # 300

Put a negative sign in front of it.
>> --300
=> 300
>> x = -300
=> -300
>> -x
=> 300

Wouldn't it just be easier to multiply it by negative one?
x * -1
That way you can go back and forth.

Most programming languages have the ABS method, however there are some that do not
Whilst I have not used Ruby before, I am familiar its a framework that runs on PHP
The abs method is available on PHP
https://www.php.net/manual/en/function.abs.php
With Ruby the syntax appears slightly different is integer.abs
https://www.geeksforgeeks.org/ruby-integer-abs-function-with-example/
But for future reference the abs method is really small to code your self.
here is how in a few different languages:
JavaScript:
function my_abs(integer){
if (integer < 0){
return integer * -1;
}
return interger;
}
Python:
def my_abs(integer):
if (integer < 0):
return integer * -1
return integer
c:
int my_abs(int integer){
if (interger < 0){
return integer * -1;
}
return integer;
}
This means should you ever find yourself with a programming language that doesnt have a built in abs method, you know how to code your own its just simply multiply any negative number by -1 as you would of gathered in my examples

Related

Integer division with rounding

I need to do integer division. I expect the following to return 2 instead of the actual 1:
187 / 100 # => 1
This:
(187.to_f / 100).round # => 2
will work, but does't seem elegant as a solution. Isn't there an integer-only operator that does 187 / 100 = 2?
EDIT
I'll be clearer on my use case since I keep getting down-voted:
I need to calculate taxes on a price. All my prices are in cents. There is nothing below 1 cent in the accountability world so I need to make sure all my prices are integers (those people checking taxes don't like mistakes... really!)
But on the other hand, the tax rate is 19%.
So I wanted to find the best way to write:
def tax_price(price)
price * TAX_RATE / 100
end
that surely returns an integer, without any floating side effect.
I was afraid of going to the floating world because it has very weird side-effects on number representation like:
Ruby strange issue with floating point multiplication
ruby floating point errors
So I found it safer to stay in the integer or the fractional world, hence my question.
You can do it while remaining in the integer world as follows:
def round_div(x,y)
(x + y / 2) / y
end
If you prefer, you could monkey-patch Fixnum with a variant of this:
class Fixnum
def round_div(divisor)
(self + divisor / 2) / divisor
end
end
187.round_div(100) # => 2
No – (a.to_f / b.to_f).round is the canonical way to do it. The behavior of integer / integer is (for example) defined in the C standard as "discarding the remainder" (see http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf page 82) and ruby uses the native C function.
This is a less know method, Numeric#fdiv
You use it like this : 187.fdiv(100).round
Not sure, but this might be what you have in mind.
q, r = 187.divmod(100)
q + (100 > r * 2 ? 0 : 1) # => 2
This should work for you :
Use syntax like this.
(number.to_f/another_number).round
Example:
(18.to_f/5).round
As #MattW already answer (+1), you'd have to cast your integers to floats.
The only other way that is less distracting can be to add .0 to your integer:
(187.0 / 100).round
However, usually we don't operate on concrete integers but variables and this method would be no use.
After some thoughts, I could:
have used BigDecimals but it feels like a bazooka to kill a bird
or I can use a custom method that wouldn't use floating division within the process, as #sawa suggests
def rounded_integer_div(numerator, denominator)
q, r = numerator.divmod(denominator)
q + (100 > r * 2 ? 0 : 1)
end
If what you want is to actually only increase the result by 1 if there's any remainder (e.g. for counting paging/batching), you can use the '%' (modula operation) for remainders checking.
# to add 1 if it's not an even division
a = 187
b = 100
result = a / b #=> 1
result += 1 if (a % b).positive?
#=> 2
# or in one line
result = (a / b) + ((a % b).zero? ? 0 : 1)

A better Ruby implementation of round decimal to nearest 0.5

This seems horrible inefficient. Can someone give me a better Ruby way.
def round_value
x = (self.value*10).round/10.0 # rounds to two decimal places
r = x.modulo(x.floor) # finds remainder
f = x.floor
self.value = case
when r.between?(0, 0.25)
f
when r.between?(0.26, 0.75)
f+0.5
when r.between?(0.76, 0.99)
f+1.0
end
end
class Float
def round_point5
(self * 2).round / 2.0
end
end
A classic problem: this means you're doing integer rounding with a different radix. You can replace '2' with any other number.
Multiply the number by two.
round to whole number.
Divide by two.
(x * 2.0).round / 2.0
In a generalized form, you multiply by the number of notches you want per whole number (say round to .2 is five notches per whole value). Then round; then divide by the same value.
(x * notches).round / notches
You can accomplish this with a modulo operator too.
(x + (0.05 - (x % 0.05))).round(2)
If x = 1234.56, this will return 1234.6
I stumbled upon this answer because I am writing a Ruby-based calculator and it used Ruby's Money library to do all the financial calculations. Ruby Money objects do not have the same rounding functions that an Integer or Float does, but they can return the remainder (e.g. modulo, %).
Hence, using Ruby Money you can round a Money object to the nearest $25 with the following:
x + (Money.new(2500) - (x % Money.new(2500)))
Here, if x = $1234.45 (<#Money fractional:123445 currency:USD>), then it will return $1250.00 (#
NOTE: There's no need to round with Ruby Money objects since that library takes care of it for you!

How to best create a random float in a range between two floats

I know that I can generate random floats with rand(max). I tried to generate a float in a range, this shouldn't be hard. But e.g rand(1.4512) returns 0, thus rand isn't calculating with floats. Now I tried a little trick, converting the thing to an integer and after randomizing a fitting number in my desired range, calculating it back to a float.. which is not working.
My question is how to do this in a better way. If there is no better way, why is this one not working? (Maybe it's too late for me, I should've started sleeping 2 hours ago..). The whole thing aims to be a method for calculating a "position" field for database records so users can order them manually. I've never done something like this before, maybe someone can hint me with a better solution.
Here's the code so far:
def calculate_position(#elements, index)
min = #elements[index].position
if #elements[index + 1].nil?
pos = min + 1
else
pos = min + (rand(#elements[index + 1].position * 10000000000) / 10000000000)
end
return pos
end
Pass a range of floats to rand
If you want to "create a random float in a range between two floats", just pass a range of floats to rand.
rand(11.2...76.9)
(Tested with Ruby 2.1)
Edit
According to the documentation: https://ruby-doc.org/core-2.4.0/Random.html
There are two different ways to write the random function: inclusive and exclusive for the last value
rand(5..9) # => one of [5, 6, 7, 8, 9]
rand(5...9) # => one of [5, 6, 7, 8]
rand(5.0..9.0) # => between 5.0 and 9.0, including 9.0
rand(5.0...9.0) # => between 5.0 and 9.0, excluding 9.0
Let's recap:
rand() will generate a (psuedo-)random
float between 0 and 1.
rand(int) will generate a
(psuedo-)random integer between 0 and
int.
So something like:
def range (min, max)
rand * (max-min) + min
end
Should do nicely.
Update:
Just tested with a little unit test:
def testRange
min = 1
max = 100
1_000_000.times {
result = range min, max
print "ERROR" if result < min || result > max
}
end
Looks fine.
In 1.9 and 2.0 you can give a range argument to rand:
irb(main):001:0> 10.times { puts rand Math::E..Math::PI }
3.0656267148715446
2.7813979580609587
2.7661725184200563
2.9745784681934655
2.852157154320737
2.741063222095785
2.992638029938756
3.0713152547478866
2.879739743508003
2.7836491029737407
=> 10
I think your best bet is to use rand() to generate a random float between 0 and 1, and then multiply to set the range and add to set the offset:
def float_rand(start_num, end_num=0)
width = end_num-start_num
return (rand*width)+start_num
end
Note: since the order of the terms doesn't matter, making end_num default to 0 allows you to get a random float between 0 and x with float_rand(x).

Decimal to Bit (Binary)

It's easy to convert Decimal to Binary and vice-versa in any language, but I need a function that's a bit more complicated.
Given a decimal number and a binary place, I need to know if the binary bit is On or Off (True or False).
Example:
IsBitTrue(30,1) // output is False since 30 = 11110
IsBitTrue(30,2) // output is True
IsBitTrue(30,3) // output is True
The function will be called a LOT of times per second, so a fast algorithm is necessary.. Your help is very much appreciated :D
Print this page out, hang above your monitor
http://graphics.stanford.edu/~seander/bithacks.html
But it's roughly something like
if ( value & (1 << bit_number) )
Really?
def IsBitTrue(num, bit):
return (num & (1 << (bit-1))) > 0
Normally, it would be 1<<bit, but since you wanted to index the LSB as 1...
Use your 'easy' function to convert the decimal number to binary, and then compare with a bit mask representing the bit you are testing.
Python
def isBitTrue( number, position ):
mask = 1 << (position-1)
return bool( number & mask )
If you number the positions from 0 (instead of 1), you can save a ton of time.
>>> isBitTrue(30,1)
False
>>> isBitTrue(30,2)
True
>>> isBitTrue(30,3)
True
bool IsBitTrue(int num , int pos)
{
return ((num>>pos-1)%2==1)
}

Sorting a string that could contain either a time or distance

I have implemented a sorting algorithm for a custom string that represents either time or distance data for track & field events. Below is the format
'10:03.00 - Either ten minutes and three seconds or 10 feet, three inches
The result of the sort is that for field events, the longest throw or jump would be the first element while for running events, the fastest time would be first. Below is the code I am currently using for field events. I didn't post the running_event_sort since it is the same logic with the greater than/less than swapped. While it works, it just seems overly complex and needs to be refactored. I am open to suggestions. Any help would be great.
event_participants.sort!{ |a, b| Participant.field_event_sort(a, b) }
class Participant
def self.field_event_sort(a, b)
a_parts = a.time_distance.scan(/'([\d]*):([\d]*).([\d]*)/)
b_parts = b.time_distance.scan(/'([\d]*):([\d]*).([\d]*)/)
if(a_parts.empty? || b_parts.empty?)
0
elsif a_parts[0][0] == b_parts[0][0]
if a_parts[0][1] == b_parts[0][1]
if a_parts[0][2] > b_parts[0][2]
-1
elsif a_parts[0][2] < b_parts[0][2]
1
else
0
end
elsif a_parts[0][1] > b_parts[0][1]
-1
else
1
end
elsif a_parts[0][0] > b_parts[0][0]
-1
else
1
end
end
end
This is a situation where #sort_by could simplify your code enormously:
event_participants = event_participants.sort_by do |s|
if s =~ /'(\d+):(\d+)\.(\d+)/
[ $1, $2, $3 ].map { |digits| digits.to_i }
else
[]
end
end.reverse
Here, I parse the relevant times into an array of integers, and use those as a sorting key for the data. Array comparisons are done entry by entry, with the first being the most significant, so this works well.
One thing you don't do is convert the digits to integers, which you most likely want to do. Otherwise, you'll have issues with "100" < "2" #=> true. This is why I added the #map step.
Also, in your regex, the square brackets around \d are unnecessary, though you do want to escape the period so it doesn't match all characters.
One way the code I gave doesn't match the code you gave is in the situation where a line doesn't contain any distances. Your code will compare them as equal to surrounding lines (which may get you into trouble if the sorting algorithm assumes equality is transitive. That is a == b, b == c implies a ==c, which is not the case for your code : for example a = "'10:00.1", b = "frog", c="'9:99:9").
#sort_by sorts in ascending order, so the call to #reverse will change it into descending order. #sort_by also has the advantage of only parsing out the comparison values once, whereas your algorithm will have to parse each line for every comparison.
Instead of implementing the sort like this, maybe you should have a TrackTime and FieldDistance models. They don't necessarily need to be persisted - the Participant
model could create them from time_distance when it is loaded.
You're probably going to want to be able to get the difference between two values, validate values as well sort values in the future. The model would make it easy to add these features. Also it would make unit testing a lot easier.
I'd also separate time and distance into two separate fields. Having dual purpose columns in the database only causes pain down the line in my experience.
I don't know ruby but here's some c-like pseudo code that refactors this a bit.
/// In c, I would probably shorten this with the ? operator.
int compareIntegers(a, b) {
int result = 0;
if (a < b) {
result = -1;
} else if (a > b) {
result = 1;
}
return result;
}
int compareValues(a, b) {
int result = 0;
if (!/* check for empty*/) {
int majorA = /* part before first colon */
int majorB = /* part before first colon */
int minorA = /* part after first colon */
int minorB = /* part after first colon */
/// In c, I would probably shorten this with the ? operator.
result = compareIntegers(majorA, majorB);
if (result == 0) {
result = compareIntegers(minorA, minorB);
}
}
return result;
}
Your routine looks fine but you could just remove the ''', ':' and '.' and treat the result as a numeric string. In other words the 10' 5" would become 1005 and 10' 4" would be 1004. 1005 is clearly more than 1004.
Since the higer order elements are on the left, it will sort naturally. This also works with time for the same reasons.
I agree that converting to integers will make is simpler. Also note that for integers
if a > b
1
elsif a < b
-1
else
0
can be simplified to a<=>b. To get the reverse use -(a <=> b).
In this scenario:
Since you know you are working with feet, inches, and (whatever your third unit of measure is), why not just create a total sum of the two values you are comparing?
So after these two lines:
a_parts = a.time_distance.scan(/'([\d]):([\d]).([\d])/)
b_parts = b.time_distance.scan(/'([\d]):([\d]).([\d])/)
Generate the total distance for a_parts and b_parts:
totalDistanceA = a_parts[0][0].to_i * 12 + a_parts[0][1].to_i + b_parts[0][2].to_i * (whatever your third unit of measure factor against the size of an inch)
totalDistanceB = b_parts[0][0].to_i * 12 + b_parts[0][1].to_i + b_parts[0][2].to_i * (whatever your third unit of measure factor against the size of an inch)
Then return the comparison of these two values:
totalDistanceA <=> totalDistanceB
Note that you should keep the validation you are already making that checks if a_parts and b_parts are empty or not:
a_parts.empty? || b_parts.empty?
For doing the sorting by time scenario, do the exact same thing except with different factors (for example, 60 seconds to a min).
Why not do
a_val = a_parts[0][0].to_i * 10000 + a_parts[0][1].to_i * 100 + a_parts[0][2].to_i
b_val = b_parts[0][0].to_i * 10000 + b_parts[0][1].to_i * 100 + b_parts[0][2].to_i
a_val <=> b_val
The numbers won't make sense to subtract, etc but they should sort ok.
You may want to check [1] and [2] are always two digits in the regexp.

Resources