Can I get the sign of the number using xpath - xpath

I want to get the sign of a number using XPath. Is there a built in function or workaround in Xpath.
As an example : when I pass -3.23 it should return "-" and for 3.23 it should return "+"

Use this XPath 2.0 expression:
'+'[$x ge 0], '-'[$x lt 0]
where $x is the number, whose sign is wanted.
This is shorter and might be slightly more efficient (having only a single comparison):
('+'[$x ge 0], '-')[1]
Use this XPath 1.0 expression:
substring('+-', 2 - ($x >= 0), 1)
Explanation:
The expression produces a substring of the string '+-' with length 1 and offset determined by 2 - ($x >= 0) -- where we use the fact that in XPath 1.0, if a Boolean value is an argument of an arithmetic operation, true() is converted to 1 and false() is converted to 0

You can get the implied sign by comparing the number to 0:
if ($num >= 0) then '+' else '-'

Related

How do I elegantly return 1.0 if the value returned is 0, in 1 line?

I have this statement:
> zv.sum(:volume).to_f || 1.0
(0.5ms) SELECT SUM("positions"."volume") FROM "positions" WHERE "positions"."volume" = $1 [["volume", 0]]
=> 0.0
What I would like to happen is if zv.sum(:volume) returns 0.0, I want it to return 1.0 instead.
I know I could do a verbose if/unless statement, but I would like to do it elegantly in 1 line above.
How do I do that?
You literally have the solution in your title and in your question (bold emphasis mine):
How do I elegantly return 1.0 if the value returned is 0, in 1 line?
What I would like to happen is if zv.sum(:volume) returns 0.0, I want it to return 1.0 instead.
So, the best way would be to use a conditional expression:
sum = zv.sum(:volume).to_f
if sum == 0.0
1.0
else
sum
end
If you want to "optimize" this, you could move the conversion to float to the very edge of the expression:
sum = zv.sum(:volume)
if sum == 0
1
else
sum
end.to_f
[Note, this assumes that the value of zv.sum(:volume) will be a number and not something like nil or a string representing a number. If that is guaranteed, this same transformation can also be applied to every single one of the following examples.]
The requirement to do something in 1 line is always trivially achievable in Ruby, since line breaks are always optional. For example:
sum = zv.sum(:volume).to_f; if sum == 0.0 then 1.0 else sum end
Or if you want to avoid using keywords:
sum = zv.sum(:volume).to_f; if sum == 0.0; 1.0 else sum end
There is also the conditional operator, but personally, I see no use for it that cannot also (and better) be served by a conditional expression:
sum = zv.sum(:volume).to_f; sum == 0.0 ? 1.0 : sum
If you want a single expression, you could inline the variable assignment into the conditional:
if (sum = zv.sum(:volume).to_f) == 0.0
1.0
else
sum
end
And of course, you can combine the two:
if (sum = zv.sum(:volume).to_f) == 0.0 then 1.0 else sum end
And with avoiding keywords:
if (sum = zv.sum(:volume).to_f) == 0.0; 1.0 else sum end
And with the (still useless) conditional operator:
(sum = zv.sum(:volume).to_f) == 0.0 ? 1.0 : sum
If you don't mind some mildly complex non-local control flow, you could do something like this:
zv.sum(:volume).to_f.tap {|sum| break 1.0 if sum == 0.0 }
Pulling out the float conversion:
zv.sum(:volume).tap {|sum| break 1 if sum == 0 }.to_f
Also, if you know something special about the sum, for example, if you know that the sum will always be either exactly 0 or greater than 1, then you could exploit that extra knowledge and maybe do something like this:
[1.0, zv.sum(:volume).to_f].max
Pulling out the float conversion:
[1, zv.sum(:volume)].max.to_f
However, please note that none of those is as readable and clear as the first version.
Also, please note that the description in your question and the code in your question don't match up, since the code doesn't do what you describe in the question.
You can use nonzero? to treat zero as a falsey value:
zv.sum(:volume).to_f.nonzero? || 1.0
or:
(zv.sum(:volume).nonzero? || 1).to_f
I usually prefer something verbose and well readable, for example :
def some_method
volume = zv.sum(:volume).to_f
return 1.0 if volume.zero?
volume
end
but if you really want your one-liner, you could do something like that :
zv.sum(:volume).to_f.yield_self { |r| r.zero? ? 1.0 : r }

conditions as boolean expression using shift operations

I learnt that condition like: (x is 4 bytes)
if (x) a = y else a = z;
can be expressed as:
a = ((x<<31)>>31)&y + (((!x)<<31)>>31)&z
I can understand what it does, but I think it is limited under the circumstance that x has all its bits of 0 (evaluated as 0, 00..00) or right most bit of 1 and rest of bits as 0 (evaluated as 1, like 00...1)
But since any non-zero value can be evaluated as true (e.g 00..010..0), then above expression doesn't work.
So how can we use shift operations in this case?

Why does string[1..-1] work but not string[-3..1]

The following block will display ruit
puts "fruit"[1..-1]
because the index starts at 1, and I think -1 represents infinity in this case
f r u i t
0 1 2 3 4
But if I want to use a reverse index, it doesn't work.
By the same logic I would expect this to return ruit, as the 0 represents infinity
puts "fruit"[-4..0]
f r u i t
-5 -4 -3 -2 -1
However this actually returns nothing. Trying it again with a 1 instead of a 0
puts "fruit"[-4..1]
f r u i t
-5 -4 -3 -2 -1
It just returns r
--
Trying it with a 5 instead of a 4
puts "fruit"[-5..1]
f r u i t
-5 -4 -3 -2 -1
Some progress is made, it returns fr.
--
However it would seem I don't understand reverse indexes. Does the -1 in [1..-1] not mean infinity? Why doesn't it work when you try to do the reverse?
It is simply that negative indices represent the position counted from the end in such a way that for a positive index i and a negative index j, they express the same position if and only if
i % string.length == j % string.length
given that the absolute value of i and j are smaller than string.length.
The cases that you claim as not working are the cases where the beginning position is on the right side of the ending position.
Negative numbers aren't "infinite", they simply represent counting from the end of the string. -1 is the last character, -2 is the second last.
"abcde"[-1]
#=> "e"
If you're doing ranges they should always be lowest..highest and in the case of String#[] you have to avoid wrapping around the end of the string. Your example with -5..1 actually wraps around, so Ruby gives up and goes with 0..1 instead. Try not to mix and match negative and positive values.
0 never represents infinity, it represents the beginning of the string. What you're experiencing here is the method trying to make do with bad arguments.
You might have a look at this question.
Short answer: in Ruby arrays, negative numbers signify the order from the end of the array, and since in Ruby
:001 > -0 == 0
=> true
then
"zero"[0] == "zero"[-0]
and you can't use a "negative zero" to refer to a different element.
So, the last element of an array is represented by -1. You can think of it as a negative array index that is one-based, as God intended.
Therefore, [1..-1] means count from the second element to the last element.

Why do numeric string comparisons give unexpected results?

'10:' < '1:'
# => true
Can someone explain me why the result in the above example is true? If I just compare '1:' and '2:' I get the result expected:
'1:' < '2:'
# => true
Strings are compared character by character.
When you compare 1: vs 2:, the comparison begins with 2 vs 1, and the comparison stops there with the expected result.
When you compare 1: vs 10:, the comparison begins with 1 vs 1, and since it is a tie, the comparison moves on to the next comparison, which is : vs 0, and the comparison stops there with the result that you have found surprising (given your expectation that the integers within the strings would be compared).
To do the comparison you expect, use to_i to convert both operands to integers.
It is character by character comparison in ASCII.
'10:' < '1:' is (49 < 49) || (48 < 58) || (58 < ?)
#=> true
'1:' < '2:' is (49 < 50) || (58 < 58)
#=> true
Left to Right boolean check is used and check breaks where true is found.
Note: It is just my observation over various example patterns.
The first character of each of your two strings are the same. And as Dave said in the comments, the second character of the first, '0', is less than ':', so the first string is less than the second.
Because the ASCII code for 0 is 48, which is smaller than the ASCII code for :, which is 58.

Why pow(-1, 0) returns 1 instead of -1?

As google suggests -10=-1. And as I understand pow() function in javascript, python and C should return the same result. But it's not true. Why?
Python:
>>> pow(-1, 0)
1
It's a precedence thing. Google thinks (-1)0 = 1, as does Python:
>>> (-1)**0
1
Any nonzero number raised by the exponent 0 is 1.
You forgot the parenthesis!
-1 ^ 0 = -(1 ^ 0) = -(1) = -1
because power operator has higher precedence.
But:
(-1)^0 = 1
See on Google
Anything to the power of 0 will result to 1.
Remember BEDMASS. Your google example executes Brackets (1^0) which is 1, then you executed Multiplication, negating your expression in the brackets to -1.
(-10) is the same as saying (-1/-1) which is 1.
In division you substract the exponent of the denominator from the exponent of the numerator.
For this rule to hold true all number elevated to the power of zero is 1. 51 / 51 = 50 = 1

Resources