In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
Most people do not understand the knowledge points of this article, "what are the five puzzles of Java language expressions?", so the editor summarizes the following, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "what are the five puzzles of Java language expressions" article.
Puzzle one: odd number
The following method is intended to determine whether its only parameter is an odd number. Does this method work correctly?
Public static boolean isOdd (int I) {returni%2==1:}
An odd number can be defined as an integer whose remainder is 1 by 2. The expression I% 2 calculates the remainder generated by dividing I by 2, so it seems that the program should work correctly. Unfortunately, it can't; it returns the wrong answer 1/4 of the time.
Why 1/4? Because half of all int values are negative, and the isOdd method will fail to judge all negative odd numbers. Calling this method on any negative integer returns false, regardless of whether the integer is even or odd. This is the consequence of Java's definition of the remainder operator (%). This operator is defined as satisfying the following identities for all int values an and all non-zero int values b:
(a _ b) * b + (a% b) = a
In other words, if you divide a by b, multiply the quotient by b, and then add the remainder, then you get the original value a. This identity has the correct meaning, but when combined with the truncated integer division operator of Java, it means that when the remainder operation returns a non-zero result, it has the same positive and negative sign as the left Operand.
When I is a negative odd number, I% 2 equals-1 instead of 1, so the isOdd method returns false incorrectly. To prevent this accident, test whether your method behaves correctly when passing negative, zero, and positive values for each numeric parameter. The problem is easy to correct. Just compare I% 2 with 0 instead of 1, and reverse the meaning of the comparison:
Public static boolean isOdd (inti) {roomni% 2 percent zero;}
If you are using the isOdd method in a performance critical (performance-critical) environment, it would be better to use the bit operator AND (&) instead of the remainder operator:
Public static boolean isOdd (inti) {return (iTun1)! = 0;}
In short, whenever you use the remainder operator, consider the symbols of operands and results. The behavior of the operator is obvious when its operands are non-negative, but not so obvious when one or both operands are negative.
Yes.
Puzzle 2: change time
Consider the problems described in the following paragraph:
Tom bought a $1.10 spark plug at an auto parts store, but his wallet was full of two-dollar bills. If he pays for the spark plug with a two-dollar bill, how much change should he give him?
Here is a program that tries to solve the above problem. What will it print?
Public class Change {public static void main (String args []) {Systemoutprintln (2.00-1.10);}}
You might naively expect the program to print 0.90, but how does it know that you want to print two decimal places?
If you know anything about the rules set in the DoubletoString document to convert values of type double to strings, you will know that the decimal printed by the program is the shortest decimal place that distinguishes a value of type double from the nearest value, with at least one place before and after the decimal point. Therefore, it seems reasonable that the program should print 0.9.
This analysis may seem reasonable, but it is not correct. If you run the program, you will find that it prints:
0.8999999999999999
The problem is that the number 1.1 cannot be accurately represented as a double, so it is represented as the closest value to it. This is the value that the program subtracts from 2. Unfortunately, the result of this calculation is not the closest to the value of 0.9. The shortest representation of the multiplier value of the result is the abominable number you see printed out.
More generally, the problem is that not all decimals can be accurately represented by binary floating-point numbers.
If you are using JDK5.0 or later, you may be tempted to correct the program by using the printf tool to set the output precision:
/ / Bad solution-still using binary floating point numbers
System.out.printf ("% .2f% n", 2.00-1.10)
This statement prints the correct result, but that doesn't mean it's a general solution to the underlying problem: it still uses double operations that are binary floating-point numbers. Floating-point operations provide a good approximation over a wide range of values, but it usually does not produce accurate results. Binary floating points are very unsuitable for currency calculations because it is impossible to accurately represent 0.1-or any other negative power of 10-as a finite-length binary decimal. One way to solve this problem is to use some integer type, such as int or long, and perform the calculation in units. If you take this route, make sure that the integer type is large enough to represent all the values you will use in the program. For the puzzle illustrated here, int is sufficient. The following is a println statement that we rewrite after we use the int type to represent the currency value in units. This version will print out the correct answer by 90 points:
Systemoutprintln + "cents")
Another way to solve this problem is to use BigDecimal that performs precise decimal operations. It can also interoperate with SQL DECIMAL types through JDBC. A word of warning here: be sure to use the BigDecimal (String) constructor, but never use BigDecimal (double). The latter constructor will create an instance with the exact "value of its parameters: new BigDecimal (1) will return a representation 0100000000000000055511151231257827021181583404541015625BigDecimal. By using BigDecimal correctly, the program can print out the desired result:
Import java.math.BigDecimal; public class Changel {public static void main (String args []) {System.out.println (newBigDecimal (2.00 ") subtract (newBigDecimal (" 1.10 "));}}
This version is not perfect because Java does not provide any language support for BigDecimal. Use
BigDecimal calculations are likely to be slower than those that use primitive types, which can be a problem for some programs that use a lot of decimal calculations, but for most programs, it doesn't matter at all.
In short, avoid using float and double; where precise answers are needed. For currency calculations, use int, long, or BigDecimal. For language designers, language support for decimal operations should be considered. One way is to provide limited support for operator overloading so that operators can be molded to work on numeric reference types, such as BigDecimal. Another way is to provide primitive decimal types, as COBOL and PL/I do.
Puzzle 3: long integers
This puzzle is called long division because the program involved is about the division of two long values. The divisor represents the number of microseconds in a day, while the divisor represents the number of milliseconds in a day. What will this program print out?
Public class Longpision {public static void main (String args []) {final long MICROS PER DAY=24*60*60*1000*1000;final long MILLIS PER DAY=24*60*60*1000;Systemoutprintln (MICROS PER DAY/ MILLIS PER DAY);}}
The puzzle looks quite intuitive. Milliseconds per day and microseconds per day are constant. For clarity, they are all expressed in the form of product. The number of microseconds per day is (24 hours / day * 60 minutes / hour * 60 seconds / minute * 1000 milliseconds / second * 1000 microseconds / milliseconds). The difference in the number of milliseconds per day is only 1000 less. When you divide the number of milliseconds per day by the number of microseconds per day, all the factors in the divisor are reduced to 1000, which is the number of microseconds per millisecond.
Both the divisor and the divisor are of type long, and the long type is so large that the two products can be easily saved without overflow. Therefore, it looks like the program must print 1000. Unfortunately, it prints 5. What's going on here?
The problem is that the calculation of the constant MICROS PER DAY does "overflow". Although the result of the calculation is suitable for long, and there is plenty of space, this result is not suitable for int. This calculation is performed entirely as an int operation, and the result is promoted to long only after the operation is complete, when it is too late: the calculation has overflowed and it returns a value 200 times smaller. Upgrading from int to long is an extension of primitive type conversion (widening primitive conversion), which retains (incorrect) values. This value is then divisible by MILLIS PER DAY, and MILLIS PER DAY's calculation is correct because it is suitable for int operations. In this way, the result of division is 5.
So why are calculations performed with int operations? For all the factors multiplied together are int values. When you multiply two int values, you will get another int value. Java does not have the feature of a target type, which is a language feature, which means that the type of variable in which the result is stored affects the type used in the calculation.
We can easily correct this program by using the long constant instead of the int constant as the first factor of each product. Doing so forces all subsequent calculations in the expression to be done using the long operation. Although this is only necessary in MICROS PER DAY expressions, it is a good way to do so in both products. Similarly, it is not always necessary to use long as the "first" value of the product, but it is a good form to do so. Starting with the long value in both calculations makes it clear that neither of them will overflow. The following program will print out the 1000 we expect:
Public class Longpision {public static void main (String args [) final long MICROS PER DAY=24L*60*60*1000*1000:final long MILLIS PER DAY=24L*60*60*1000;SystemoutprintlnMICROS PER DAY MILLIS PER DAY);}}
The lesson is simple: when you are manipulating large numbers, beware of overflows-it is a silent killer. Even if the variable used to hold the result appears large enough, it does not mean that the calculation to produce the result has the correct type. When you are in doubt, use the long operation to perform the entire calculation.
The lesson that language designers can learn from this is that it may be worth doing to reduce the likelihood of silent spillover. This can be achieved by supporting operations that do not produce silent overflows. The program can throw an exception instead of directly overflowing. As Ada does, or they can automatically switch to a larger internal representation when needed to prevent overflow, as Lisp does. Both approaches may suffer performance losses associated with them. Another way to reduce silent overflows is to support target typing, but doing so significantly increases the complexity of the type system.
Puzzle 4: primary question
Come on, the previous puzzle is a bit tricky, but it's about division, and everyone knows that division is troublesome. So the following program only involves addition, what will it print?
Public class Elementary {public static void main (String] args) {Systemoutprintln (12345 / 54321);}}
On the face of it, it looks like a simple puzzle-so simple that you can solve it without paper and pen. The bits of the left Operand of the plus sign are arranged in ascending order from 1 to 5, while the right Operand is arranged in descending order. Therefore, the corresponding sum is still constant, and the program must print 66666. There is only one problem with such an analysis: when you run the program, it prints out 17777. Is it that Java is biased against printing such extraordinary numbers? Somehow, this doesn't seem like a reasonable explanation.
Things are often different from what they seem. Take this problem as an example, it does not print out the output we want. Take a closer look at the two operands of the + operator. We added 12345 of an int type to 54321 of a long type. Notice the slight difference between the number 1 at the beginning of the left Operand and the lowercase letter 1 at the end of the right Operand. There is an acute angle between the horizontal stroke of the number 1 (called "arm") and the vertical stroke (called "stem"), while there is a right angle between the arm of the lowercase letter l and the stem.
Before you yell "disgusting!" You should have noticed that this problem has indeed caused confusion before, and there is a lesson here: in long literal constants, be sure to use an uppercase L and never a lowercase 1. In this way, the source of the confusion caused by this puzzle can be completely cut off.
System.out.println (12345-5432L)
Similarly, avoid using a separate 1 letter as the variable name. For example, it is difficult to tell whether it prints out listing 1 or the number 1 by looking at the following code snippet.
List l=new ArrayList (); l.add ("Foo"); System.outprintln (1)
In short, the lowercase l and the number 1 are almost the same in most typewriter fonts. To avoid confusion among readers of your program, never use a lowercase 1 as the end of a long literal constant or as a variable name. Java inherits a lot from the C programming language, including the syntax for long literal constants. Maybe it was a mistake to allow long literal constants to be written in lowercase 1.
Riddle 5: the fun of hexadecimal
The following program adds two hexadecimal (hex) literal constants and then prints out the hexadecimal result. What will this program print out?
Public class JoyOfHex {public static void main (String [] args) {System.out.println (Long.toHexString (0x100000000L+0xcafebabe));}}
It seems obvious that the program should print out 1cafebabe. After all, this is indeed the sum of the hexadecimal number 10000000016 and cafebabe16. The program uses a long operation, which can support 16-bit hexadecimal numbers, so operation overflow is impossible.
However, if you run the program, you will find that it prints out cafebabe without any leading 1. This output represents a 32-bit low of the correct result, but somehow bit 33 is lost.
It looks as if the program is performing an int operation instead of a long operation, or forgetting to add the first Operand. What's going on here?
Decimal literal constants have a good attribute, that is, all decimal literal constants are positive, while hexadecimal and octal literal constants do not. To write a negative decimal constant, you can concatenate a decimal literal constant with the unary inverse operator (-). In this way, you can write any int or long value in decimal, whether it is positive or negative, and the negative decimal constant can be clearly identified by a minus sign. But hexadecimal and octal literal constants are not the case. They can have positive and negative values. If the highest bits of hexadecimal and octal literal constants are set, they are negative. In this program, the number Oxcafebabe is an int constant whose highest bit is set, so it is a negative number. It is equal to the decimal value-889275714.
The addition performed by the program is a "mixed type of computation (mixed-type computation). The left Operand is of type long and the right Operand is of type int." To perform this calculation, Java promotes the value of the int type to a long type by widening the primitive type conversion, and then adds the values of the two long types. Because int is a signed integer type, this conversion performs a conformant extension: it raises the value of the negative int type to a numerically equivalent value of the long type. The right Operand 0xcafebabe of this addition is promoted to the numeric 0xffffffffcafebabeL of type long. This number is then added to the left Operand 0x100000000L. When examined as an int type, the 32-bit high of the signed extended right Operand is-1, while the high 32-bit of the left Operand is 1, and the sum of these two numbers results in 0, which explains why leading 1 is lost in the program output. The following is a handwritten addition implementation. (the number above addition is carry.)
11111110xffffffffcafebabeL+0x0000000100000000L0x00000000cafebabeL
The correction of the program is very simple, as long hexadecimal literal constant is used to represent the right Operand. This avoids destructive symbolic extensions, and the program can print out the desired result 1cafebabe:
Public class JoyOfHex {public static void main (String [] args) {System.outprintln (LongtoHexString (0x100000000L+0xcafebabeL));}}
The lesson of this puzzle is that mixed-type calculations can be confusing, especially hexadecimal and octal literal constants that can represent negative values without an explicit minus sign. To avoid this dilemma, it is usually best to avoid mixed types of computing. For language designers, consideration should be given to supporting unsigned integer types, thus eliminating the possibility of symbolic extensions. There may be an argument that negative hexadecimal and octal literal constants should be disabled, but this can frustrate programmers, who often use hexadecimal literal constants to represent values whose symbols don't mean anything.
The above is the content of this article on "what are the five puzzles of Java language expressions". I believe we all have a certain understanding. I hope the content shared by the editor will be helpful to you. If you want to know more about the relevant knowledge, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.