Your skill will accomplishwhat the force of many cannot PerlMonks

### Re^4: &1 is no faster than %2 when checking for oddness. Oh well. ("bug"?)

by tye (Sage)
 on Nov 16, 2006 at 23:23 UTC Need Help??

I don't understand. Are you asserting that it is a bug that 1e11 & 1 doesn't die (or fail in some other way)? If so, then you didn't counter my point that %2 works for a ton more cases than &1. No, %2 doesn't work on huge numbers that don't fit accurately into an NV (but does work on huge numbers when you use an appropriate format for the huge numbers) nor on Russian words nor JPEG images. And, yes, writing "2" as "1.99..." leads to surprises. Of course, &1 doesn't fair any better on these straw men.

Or are you asserting that &1 should work directly on NVs? That'd be a non-trivial design change, so I wouldn't casually call that a "bug". If that were implemented in a way that made &1 work for detecting odd NVs, then it'd probably at least make it easier to see the speed difference between it and %2 (but then you'd be forced to use %2 anyway because it'd be trivially faster, I bet).

I'm shocked people can spend so much effort just trying to see if there is a speed difference between the two when it so clearly obvious (because it is so hard to even see a difference) that any difference that there is doesn't matter in the slightest.

I use %2 because 11- and 16-digit numbers are real, practical, useful things to be able to deal with right now (and I can even upgrade to some module for even bigger numbers with no changes). It is a "best practice" and most of the time works great (it always works great unless you have other problems, like using inappropriate storage for the numbers you are dealing with).

&1 often works but has zero real advantages (the speed difference, if anyone manages to show that there even is one, is of no consequence, even in fanciful extreme situations), except for people who can't equate "even" with "divisible by two" with "has 0 remainder when divided by two" and are only comfortable with equating "even" with "has some bit unset" (in what representation?).

Using &1 means that your code won't work when someone uses it with a perfectly valid Perl number that doesn't happen to fit in a UV. That is a real, practical disadvantage.

/me regrets having posted this already.

Enjoy.

- tye

Replies are listed 'Best First'.
Re^5: &1 is no faster than %2 when checking for oddness. Oh well. ("bug"?)
by BrowserUk (Patriarch) on Nov 17, 2006 at 01:56 UTC

/me too.

Why is it that you can never state your position without denigrating those who's opinion differs?

Others may allow you to get away with your unveiled ad homonym attacks and overbearing sarcasm, but whether they are aimed at me or others, I will call you on it every time.

I've explained my preference for my choice elsewhere in this thread, but nowhere have I attributed it to performance. The issue of performance is purely one of countering a bad benchmark. Nothing more.

Which makes "(but then you'd be forced to use %2 anyway because it'd be trivially faster, I bet)." nothing but another example of your overbearing sarcasm.

I'm shocked people can spend so much effort just trying to see if there is a speed difference between the two when it so clearly obvious (because it is so hard to even see a difference) that any difference that there is doesn't matter in the slightest.

Again. You attribute me with motives for which there is no basis. I didn't post the original benchmark. I simply drew attention to its flaws and cleaned it up.

even in fanciful extreme situations)

More denigration. Once again based upon nothing in this thread.

people who can't equate "even" with "divisible by two" with "has 0 remainder when divided by two" and are only comfortable with equating "even" with "has some bit unset"

Why use the word "comfortable"? It certainly isn't derived from anything I've said in this thread. Nor anything anyone else has said that I've read. Again, you attempt to make the arguments personal instead of technical. For what purpose?

Using &1 means that your code won't work when someone uses it with a perfectly valid Perl number that doesn't happen to fit in a UV.

If I use & 1 in my code, it is because I know that values I am applying it to are integers that will not exceed that range of values to which the application of bit-wise operators can be applied. That is a part of my job as a programmer.

If someone else comes along and takes that code and utilises it in a situation where that does not hold true, then it is their job as programmers to recognise that and adjust the code accordingly. (See below!)

If your argument is that I should not be aware nor care what storage format is used to represent numbers and should always code such that all operations can be applied to the full range of Perl's numeric representations, why does perl have bitwise numeric operations? There is no logical way they could ever be used in those circumstances!

You say "it always works great unless you have other problems, like using inappropriate storage for the numbers you are dealing with).", but how is using

```\$n = 9_007_199_254_740_992; print 'Even' unless \$n % 2;;
Even

"appropriate", but not

```++\$n; print 'Even' unless \$n % 2;;
Even
Are you asserting that it is a bug that 1e11 & 1 doesn't die (or fail in some other way)?

Yes.

Are you seriously suggesting that you would design a new language that silently converts 99_999_999_999 into 4294967295?

So, despite another piece of your sarcasm addressed to a straw man of your own construction "Or are you asserting that &1 should work directly on NVs?", that again appears nowhere else in the thread.

Yes, I am suggesting that perl's silent conversion of 99_999_999_999 into 4_294_967_295 is a bug. It may be a behaviour that will never change due to backward compatibility, but I cannot believe it was a deliberate design decision, and that makes it a bug.

The greater range that one method continues to work over (before again silently failing), is pretty irrelevant on two counts.

1. For the great majority of applications that use oddness tests, the range of an IV or UV is more than sufficient. Think carefully about that statement, from the perspective of real code, rather than the hypothetical.

If attempting to "future proof" applications by using NVs where we know IVs or UVs were more than sufficient was a good idea.

• Why do we bother with IVs and UVs at all?
• Why don't we use bignum in every script we write?
2. Most importantly, if I have chosen to use & on a particular variable for this purpose--because I know it is sufficient for this purpose--then it's quite possible, even likely that I will have
• used other boolean operations on that same variable for other purposes.
```my( \$loWord, \$hiWord ) = ( \$n & 0xffff, \$n >> 16 );
• Or use pack or unpack on that variable.
```print unpack 'N', pack 'N', 99_999_999_999;;
4294967295
• Or used (s)printf on that variable;
```printf "%d\n", 99_999_999_999;;
-1
• Or used my knowledge of the size of that variable in some math somewhere.
```my \$indexSize = 4 * \$noLines;
• Or any number of other operations that require that variable to be a 32-bit integer of one form or other.

If I code a 'oddness' test on that variable using % 2 somewhere in the code, then I am asking for the next guy that comes along and sees that to assume that extending the range of use for that variable is safe. When I know it is not.

This is the exact counter argument to your

Using &1 means that your code won't work when someone uses it with a perfectly valid Perl number that doesn't happen to fit in a UV. That is a real, practical disadvantage.

By using & 1 for oddness testing, I am clearly flagging the intended design range for the variable. Using % 2 would be to conceal that information.

The bottom line with this, as with so many "future proofing" arguments, is that you cannot predict the future, and trying is futile as it creates as many potential problems as it potentially solves. You cannot protect the future programmer against the effects of the changes they might make.

It is, and must be incumbent on the future/maintenance programmer to understand the code he is modifying before he makes his modifications. And all the arguments that suggest that you can prevent future problems by allowing the programmer to leap in and make changes without fully understanding their implications, are bogus.

[ I'll ignore most of your extensive, off-topic complaints where you try to attribute me with motives based on your personal baggage. I'll note a couple of them, however, in the course of trying to finish the technical argument, and I will address one directly, at least as an example (since it was less off-topic). ]

Are you asserting that it is a bug that 1e11 & 1 doesn't die (or fail in some other way)?

Yes.

Are you seriously suggesting that you would design a new language that silently converts 99_999_999_999 into 4294967295?

I don't believe I suggested any such thing. But thanks for trying to insult me based on ideas you've made up and attributed to me. (See how easy it is to claim that? No, I don't find this claim to be a stretch, but I prefer to avoid such interpretations. Also, I don't find it difficult to intepret your question simply as a technical question; just in case you were actually trying to be insulting.)

But, no, I don't have a big problem with converting a value that is too large to fit into a UV into the maximal value that does fit (and caching that value and only using it when one forces Perl to perform a UV-only operation on the scalar). Looking at similar situations in Perl, issuing a warning seems appropriate, but adding such wouldn't be an unmixed blessing.

So, despite another piece of your sarcasm addressed to a straw man of your own construction "Or are you asserting that &1 should work directly on NVs?", that again appears nowhere else in the thread.

FYI, there was no sarcasm in that sentence. I was simply trying to figure out an argument that you might have been trying to make that actually countered the point of my node (that %2 works in more cases than &1). I was giving you the benefit of the doubt that you understood my point and disagreed with it and I just didn't understand your point.

I stated, in effect, "&1 doesn't work on many valid NV values" and you replied "That's just a bug." The most straight-forward interpretation of your sentence, when given in response to what I wrote, is that you think that "&1 would work on as many NV values as %2, if it weren't for a bug in Perl." So I entertained that most straight-forward interpretation. I don't find such an idea (& working directly on NVs) to be ridiculous.

It is, and must be incumbent on the future/maintenance programmer to understand the code he is modifying before he makes his modifications.

I wasn't speaking of future programmers nor of modifying code. I was speaking of writing code that simply works on a much wider range of values and without a single technical drawback. That makes it a trivial decision for me to label such a practice as a "best practice" and to adopt it.

The bottom line with this, as with so many "future proofing" arguments, is that you cannot predict the future, and trying is futile as it creates as many potential problems as it potentially solves. [emphasis added]

I didn't see you present any future potential problems of using %2. You have one point that boils down to style; you state that using %2 "conceal"s the fact that elsewhere one may have limited the potential range of a value. I disagree both with that claim ("conceal") and with the implied idea that it is best to repeat "this is a UV" at every single operation one performs on a value that one has elsewhere decided will only ever be a UV. And I don't consider that a potential future problem. Especially since I was not talking about modifying code.

To make it extremely simple, consider the code:

```my \$num= shift @ARGV;
print "Your number (\$num) is odd.\n"   if  \$num & 1;

It takes absolutely no modification of the code for it go from only being used on small integers to being used on values that don't fit into a UV. So replacing that with:

```my \$num= shift @ARGV;
print "Your number (\$num) is odd.\n"   if  \$num % 2;

very much future-proofs the code against such a change, even though I wrote the code fully intending that I'd only use it on small integers. By your claim, I must have introduced as many problems by doing that as I have solved. I actually can't come up with any. Perhaps you will, but I do believe that I can do a decent job of "predicting the future" when it comes to what the above code would receive in @ARGV if the code is not modified. And my improved code does in fact deal with a large number of potential and reasonable inputs that the original code did not, while also not failing to deal with any potential and reasonable inputs that the prior code dealt with correctly.

You wrote a lot about bit-twiddling (and similar) code and using &1. Well, if I'm twiddling bits, then if I happen to want to extract the lowest bit of an int, then I won't be trying to "check for oddness" and so it'd be quite silly to use %2, especially in the same expression with a bunch of bit-twiddling operations.

If I'm doing some work on a scalar and one step is "check for oddness" and there are other steps that I do in a way that would fail if used on a value that wouldn't fit into a UV, then I'd still use %2, because there is no penalty in doing so. If I later realize that my initial assumption (about the handling of non-UV values not being required) is no longer valid, then I have one less change required of my code in order to fix it. Gee, I will have predicted the future and saved myself work in the long run without incurring any extra work in the short term. I may have even saved myself work in the short term because, having already adopted %2 as a "best practice", I didn't waste any time debating about whether I should use it or &1 when "checking for oddness".

One can claim that such predictions are futile and almost never come true, but my experience shows otherwise. And even if it didn't come true, I've not lost anything as %2 works just as well as &1 for testing the oddness of all of the values that &1 works for that on.

It is, and must be incumbent on the future/maintenance programmer to understand the code he is modifying before he makes his modifications. [original emphasis]

That doesn't mean that making the code easier to update is a bad thing. I like to make code easier to update, and my predictions of the future have come true often enough that I've repeatedly been glad that I've attempted that.

- tye

[ I'm sorry that you still can't deal. I'll try to remember to go back to replying to you anonymously for a while. Perhaps you'll read your sig enough times that eventually you'll be able to follow it. (Hmm, you omitted it from that last post. I won't try to guess at your motive, though, as that would be rude.) ]

To make it extremely simple, consider the code:

At last, a technical argument. For safety.

This

```sub odd {
die 'Out of integer range'
if \$_[ 0 ] & 0xffffffff != \$_[ 0 ]; ## Should be done by perl!
return \$_[ 0 ] & 1;
}

Versus this

```sub odd {
my \$num= shift @ARGV;
die 'Number too big to test for oddness'
if \$num > 9_007_199_254_740__992;

die 'Number too small to test for oddness'
if \$num < -9_007_199_254_740__992;

die 'Cannot test #INFinity for oddness'
if \$num eq '1.#INF';

die 'Cannot test negative #INFinity for oddness'
if \$num eq '-1.#INF';

die 'Cannot test #IND for oddness'
if \$num eq '1.#IND';

die 'Cannot test negative #IND for oddness'
if \$num eq '-1.#IND';

die 'Cannot test a non number for oddness'
if \$num eq '1.#QNAN;

die 'Cannot test negative non number for oddness'
if \$num eq '-1.#QNAN;

die 'Cannot test a non-integer for oddness'
if int( \$num ) != \$num;

return \$num % 2 ? 1 : 0;
}

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
A reply falls below the community's threshold of quality. You may see it by logging in.

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://584632]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (2)
As of 2024-04-20 10:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found