Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm new to Java and all things programming so I will explain this the best I can.
I'm trying to create a simple program that includes a method that calls on a parameter to print a sequence of descending numbers. This numerical sequence starts at a number given by the user and stops at 1.
The assignment is as follows:
Create the following method in the exercise template: public static void printFromNumberToOne(int number). It should print the numbers from the number passed as a parameter down to one.
e.g.
public static void main(String[] args) {
printFromNumberToOne(5);
sample output:
5
4
3
2
1
When I run the program I have written so far to solve the exercise, it starts at 5, and descends beyond 1 indefinitely into negative integers (5,4,3,2,1,0,-1,-2,-3,∞...)
I need to insert a break or the condition that the loop stops running once i=0, but I have no idea how to do this without getting an error message. Where am I going wrong?
here's the method parameter in question:
public static void printFromNumbertoOne(int num) {
int i = 5;
while (i <= num) {
System.out.println(i--);
In Java, a while loop will continue running as long as it's condition (i <= num in your case) is true. With i-- you are decreasing i on every run of the loop and since i starts at 5 and num is also 5 in your example, i <= num is always true and your loop will run forever.
I would recommend to use while (num > 0) instead and change the next line to System.out.println(num--);. Thereby the loop would run as long as num is bigger than 0 and num is being decreased on every loop run.
Please be aware that this version would still run forever if you start the function with a negative value as in printFromNumbertoOne(-5);. To handle that you should also include a check whether num is positive.
Edit: I'm sorry, I was a bit tired yesterday. It would not actually run forever, instead the loop while (num > 0) would just not run when num is negative or 0, since the condition would never be true.
Related
I've tried searching for help but I haven't found a solution yet, I'm trying to repeat math.random.
current code:
local ok = ""
for i = 0,10 do
local ok = ok..math.random(0,10)
end
print(ok)
no clue why it doesn't work, please help
Long answer
Even if the preferable answer is already given, just copying it will probably not lead to the solution you may expect or less future mistakes. So I decided to explain why your code fails and to fix it and also help better understand how DarkWiiPlayer's answer works (except for string.rep and string.gsub).
Issues
There are at least three issues in your code:
the math.random(m, n) function includes lower and the upper values
local declarations hide a same-name objects in outer scopes
math.random gives the same number sequence unless you set its seed with math.randomseed
See Detailed explanation section below for more.
Another point seems at least worth mentioning or suspicious to me, as I assume you might be puzzled by the result (it seems to me to reflect exactly the perspective of the C programmer, from which I also got to know Lua): the Lua for loop specifies start and end value, so both of these values are included.
Attempt to repair
Here I show how a version of your code that yields the same results as the answer you accepted: a sequence of 10 percent-encoded decimal digits.
-- this will change the seed value (but mind that its resolution is seconds)
math.randomseed(os.time())
-- initiate the (only) local variable we are working on later
local ok = ""
-- encode 10 random decimals (Lua's for-loop is one-based and inclusive)
for i = 1, 10 do
ok = ok ..
-- add fixed part
'%3' ..
-- concatenation operator implicitly converts number to string
math.random(0, 9) -- a random number in range [0..9]
end
print(ok)
Detailed explanation
This explanation makes heavily use of the assert function instead of adding print calls or comment what the output should be. In my opinion assert is the superior choice for illustrating expected behavior: The function guides us from one true statement - assert(true) - to the next, at the first miss - assert(false) - the program is exited.
Random ranges
The math library in Lua provides actually three random functions depending on the count of arguments you pass to it. Without arguments, the result is in the interval [0,1):
assert(math.random() >= 0)
assert(math.random() < 1)
the one-argument version returns a value between 1 and the argument:
assert(math.random(1) == 1)
assert(math.random(10) >= 1)
assert(math.random(10) <= 10)
the two-argument version explicitly specifies min and max values:
assert(math.random(2,2) == 2)
assert(math.random(0, 9) >= 0)
assert(math.random(0, 9) <= 9)
Hidden outer variable
In this example, we have two variables x of different type, the outer x is not accessible from the inner scope.
local x = ''
assert(type(x) == 'string')
do
local x = 0
assert(type(x) == 'number')
-- inner x changes type
x = x .. x
assert(x == '00')
end
assert(type(x) == 'string')
Predictable randomness
The first call to math.random() in a Lua program will return always the same number because the pseudorandom number generator (PRNG) starts at seed 1. So if you call math.randomseed(1), you'll reset the PRNG to its initial state.
r0 = math.random()
math.randomseed(1)
r1 = math.random()
assert(r0 == r1)
After calling math.randomseed(os.time()) calls to math.random() will return different sequences presuming that subsequent program starts differ at least by one second. See question Current time in milliseconds and its answers for more information about the resolutions of several Lua functions.
string.rep(".", 10):gsub(".", function() return "%3" .. math.random(0, 9) end)
That should give you what you want
I understand recursion and what the advantages it brings to writing code efficiently. While I can code recursive functions, I cannot seem to wrap my head around how they work. I would like someone to explain me recursion instinctively.
For example, this code:
int fact(int n)
{ if n<0:
return -1
elif n==0:
return 1
else
return n*fact(n-1)
}
These are some of my questions:
Let's say n=5. On entering the function,the control goes to the last return statement since none of the previous conditions are satisfied.
Now, roughly, the computer 'writes' something like this: 5*(fact(4))
Again, the fact() function is called and the same process gets repeated except now we have n=4.
So, how exactly does the compiler multiply 5*4 and so on until 2 since its not exactly 5*4 but 5*fact(4). How does it 'remember' that it has to multiply two integers and where does it store the temporary value since we haven't provided any explicit data structure?
Again let's say n=5. The same process goes on and eventually n gets decremented to 0. My question is why/how doesn't the function simply return 1 as stated in the return statement. Similar to my previous question, how does the compiler 'remember' that it also has 180 stored for displaying?
I'd be really thankful if someone explains this to me completely so that can understand recursion better and intuitively.
Yeah, for beginners recursion can be quite confusing. But, you are already on the right track with your explanation under "1.".
The function will be called recursively until a break condition is satisfied. In this case, the break condition is satisfied when n equals 0. At this point, no recursive calls will be made anymore. The result of each recursive call is returned to the caller. The callers always "wait" until they get a result. That's how the algorithm "knows" the receiver of the results. The flow of this procedure is handled by the so called stack.
Hence, in your informal notation (in this example n equals 3):
3*(fact(2)) = 3*(2*fact(1)) = 3*(2*(1*fact(0))).
Now, n equals 0. The inner fact(0) therefore returns 1:
3*(2*(1*(1)))) = 3*(2*(1)) = 3*(2) = 6
You can see a bit like this
The function fact(int n) is like a class and every time you call fact(int n) you create an instance of that class. By creating them (calling them) from the same function, you are creating a chain of instances. Once you reach break condition, those functions start returning one by one and the value they returned to calculate a new value in the return statement return n*fact(n-1) e.g. return 3*fact(2);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm reading someone else's code and they separately increment their for loop counter inside the loop, as well as including the usual afterthought. For example:
for( int y = 4; y < 12; y++ ) {
// blah
if( var < othervar ) {
y++;
}
// blah
}
Based on the majority of code others have written and read, should I be expecting to see this?
The practice of manipulating the loop counter within a for loop is not exactly widespread. It would surprise many of the people reading that code. And surprising your readers is rarely a good idea.
The additional manipulation of your loop counter adds a ton of complexity to your code because you have to keep in mind what it means and how it affects the overall behavior of the loop. As Arkady mentioned, it makes your code much harder to maintain.
To put it simply, avoid this pattern. When you follow "clean code" principles, especially the single layer of abstraction (SLA) principle, there is no such thing as
for(something)
if (somethingElse)
y++
Following the principle requires you to move that if block into its own method, making it awkward to manipulate some outer counter within that method.
But beyond that, there might be situations where "something" like your example makes; but for those cases - why not use a while loop then?
In other words: the thing that makes your example complicated and confusing is the fact that two different parts of the code change your loop counter. So another approach could look like:
while (y < whatever) {
...
y = determineY(y, who, knows);
}
That new method could then be the central place to figure how to update the loop variable.
I beg to differ with the acclaimed answer above. There is nothing wrong with manipulating loop control variable inside the loop body. For example, here is the classical example of cleaning up the map:
for (auto it = map.begin(), e = map.end(); it != e; ) {
if (it->second == 10)
it = map.erase(it);
else
++it;
}
Since I have been rightfully pointed out to the fact that iterators are not the same as numeric control variable, let's consider an example of parsing the string. Let's assume the string consists of a series of characters, where characters prefixed with '\' are considered to be special and need to be skipped:
for (size_t i = 0; i < s_len; ++i) {
if (s[i] == '\\') {
++i;
continue;
}
process_symbol(s[i]);
}
Use a while loop instead.
While you can do this with a for loop, you should not. Remember that a program is like any other piece of communication, and must be done with your audience in mind. For a program, the audience includes the compiler and the next person to do maintenance on the code (likely you in about 6 months).
To the compiler, the code is taken very literally -- set up a index variable, run the loop body, execute the increment, then check the condition to see if you are looping again. The compiler doesn't care if you monkey with the loop index.
To a person however, a for loop has a specific implied meaning: Run this loop a fixed number of times. If you monkey with the loop index, then this violates the implication. It's dishonest in a sense, and it matters because the next person to read the code will either have to spend extra effort to understand the loop, or will fail to do so and will therefore fail to understand.
If you want to monkey with the loop index, use a while loop. Especially in C/C++/related languages, a for loop is exactly as powerful as a while loop, so you never lose any power or expressiveness. Any for loop can be converted to a while loop and vice versa. However, the next person who reads it won't depend on the implication that you don't monkey with the loop index. Making it a while loop instead of a for loop is a warning that this kind of loop may be more complicated, and in your case, it is in fact more complicated.
If you increment inside the loop, make sure to comment it. A canonical example (based on a Scott Meyers Effective C++ item) is given in the Q&A How to remove from a map while iterating it? (verbatim code copy)
for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
if (must_delete)
{
m.erase(it++); // or "it = m.erase(it)" since C++11
}
else
{
++it;
}
}
Here, both the non-constant nature of the end() iterator and the increment inside the loop are surprising, so they need to be documented. Note: the loop hoisting here is after all possible so probably should be done for code clarity.
For what it's worth, here is what the C++ Core Guidelines has to say on the subject:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-loop-counter
ES.86: Avoid modifying loop control variables inside the body of raw
for-loops
Reason The loop control up front should enable correct
reasoning about what is happening inside the loop. Modifying loop
counters in both the iteration-expression and inside the body of the
loop is a perennial source of surprises and bugs.
Also note that in the other answers here that discuss the case with std::map, the increment of the control variable is still only done once per iteration, where in your example, it can be done more than once per iteration.
So after the some confusion, i.e. close, reopen, question body update, title update, I think the question is finally clear. And also no longer opinion based.
As I understand it the question is:
When I look at code written by others, should I be expecting to see "loop condition variable" being changed in the loop body ?
The answer to this is a clear:
yes
When you work with others code - regardless of whether you do a review, fix a bug, add a new feature - you shall expect the worst.
Everything that are valid within the language is to be expected.
Don't make any assumptions about the code being in acordance with any good practice.
It's really better to write as a while loop
y = 4;
while(y < 12)
{
/* body */
if(condition)
y++;
y++;
}
You can sometimes separate out the loop logic from the body
while(y < 12)
{
/* body */
y += condition ? 2 : 1;
}
I would allow the for() method if and only if you rarely "skip" an item,
like escapes in a quoted string.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have some code from a larger program. This part generate random numbers within a range and checks for duplicates. I have placed print statement to help with getting a handle on scope. If a duplicate is detected I want a new random number to be generated. The code works but I think an experience programmer would laugh at how ineptly it does it. So I was hoping for some guidance on how to improve this code.
Code Extract
-- prepare set of numbers to choose from
local r = {}
for i = c-8, c+12 do
table.insert(r, i)
end
-- take some numbers from the set
for i = 1, #options do
options[i] = table.remove(r, math.random(#r))
end
-- options[] is guaranteed to not contain duplicates
Here's an alternative for when you're only going to pull a few numbers from a large set and place them in options. It might be a tad faster than Egor's in that situation. For the following, assume the random number between integer A and integer B, and you're looking for C unique numbers:
options = {}
local taken = {}
for i = 1,C do
repeat
options[i] = math.random(A,B)
while taken[options[i]] ~= nil
taken[options[i]] = true
end
You can improve it by setting an array to record whether a number has already been added or not. Here is a sample pseudo-code.
//create a list whichs length is the num of possible numbers
numAddedState <- createList((upperBound-lowerBound+1),false)
generatedNums <- []
while length(generatedNums) < requiredLength {
num <- random(lowerBound, upperBound)
if (numAddedState[num - lowerBound]) {
//add the number into list and change the added state of this number to true
generatedNums.append(num)
numAddedState[num - lowerBound] <- true
}
else {
print(num + " is dup")
}
}
return generatedNums
if you need to generate float point numbers, you can replace the numAddedState list with a list of list, which stores grouped numbers. By doing that you can reduce the num of item you need to check.
Here is an example which group numbers using floor()
//create a list whichs length is the num of possible numbers and default value is an empty list
numsAdded <- createList((floor(upperBound)-floor(lowerBound+1)),[])
generatedNums <- []
while length(generatedNums) < requiredLength {
num <- random(lowerBound, upperBound) //generate float point number
for numbers in numsAdded[floor(num)] {
if numbers == num {
print(num + " is dup")
continue
}
}
numsAdded[floor(num)].append(num)
generatedNums.append(num)
}
return generatedNums
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I cannot figure it out why the for loop is created in spite of having while loop.
In my opinion, they are the same even through someone says that the while loop is used when we do not know an iteration number. In that case, we can also use for loop, can't we?
For example,
For loop:
for (;true;)
{
document.write("Hello World <br>");
if(somecondition){
break;
}
}
While loop:
while (true)
{
document.write("Hello World <br>");
if(somecondition){
break;
}
}
Moreover, the complexity of the two kinds of loops are the equal. So, why the loops do not be deleted and rest only one kind?
Short answer: They are both syntactic sugar that make interpreting the code easier for a programmer, not a machine.
Neither approach you given is no more or less valid than the other, and its true that every for loop can be written as a while loop. The difference is that it makes it more readable to another programmer.
Lets look at Python for an example:
for line in file.readline():
I don't need to see anything else in this block of code to know its intent. Its reading a file, where as in this example:
readline = file.readline()
while readline != "":
# some code
readline = file.readline()
It is much less clear what is happening, but the intent is there. Worst still is this:
while true:
readline = file.readline()
if readline == "":
break
I now need to read further into the loop to gain the same insight. As stated above, while loops and for loops offer programmers ways to make more readable and thus more maintainable code.
Indeed, anything you can do using a for loop can also be accomplished with a while loop. The following two are equivalent:
for (initialCondition; test; nextStep) {
doSomething;
}
and
initialCondition;
while (test) {
doSomething;
nextStep;
}
So why do we have the for loop at all? There are two reasons.
First, the pattern in the second code snippet is very common (initialize something, then loop while updating on each step until a condition fails). Because it's so common, many language designers considered it worthwhile to have a special syntax for it.
Second, moving iteration variables (e.g. i or j) out of the loop body and inside the for makes it easier for compilers and interpreters to detect certain classes of error (or perhaps even forbid them). For example, if I write (in MATLAB because I happen to have it open)
for i = 1:10
i = i + 5; // The body of
disp(i); // the loop.
end
then MATLAB presents me with a warning -- "Line 2: Loop index 'i' is changing inside a FOR loop". If I instead wrote it as a while loop:
i = 1;
while i <= 10
i = i + 5; // The body of
disp(i); // the loop.
i = i + 1;
end
Uh-oh! Not only do I no longer get a warning from MATLAB, now my code is incorrect! Modifying the iteration variable in the body of the loop is dangerous, and it's rarely the case that you mean to do it. Writing "initialize, test, update" loops as for loops rather than while loops helps protect you from this class of error.
You are correct, for-loops can be converted to while-loops and vice-versa. You can even convert them to do-while loops.
It is the same with if and switch. Why having a switch when the same can be done with an if as well?
I guess it mainly exists for readability and maintainance reasons. Consider the following code:
int i=0;
while(i < array.length){
doStuff(array[i]);
i++;
}
Now, another developer adds functionality around this loop:
int i=0;
do();
some();
i = other(); // oops, didn't see that i was used for the loop
stuff();
while(i < array.length){
doStuff(array[i]);
i++;
doMoreStuff(array[i]); // oops, did't see i was already incremented
}
With
for(int i=0; i<array.length; i++){
doStuff(array[i]);
doMoreStuff(array[i]);
}
It is easier to read (you know when the loop starts and when it ends)
It is more error robust (i is scoped to the for loop)
Therefore, it is easier to maintain
Yes, I think you don't need neither of them:
Label1:
document.write("Hello World <br>");
if(somecondition) goto Label2;
goto Label1;
Label2:
They're semantically the equivalent. for(x;y;z) { foo; } is equivalent to x; while (y) { foo; z; }. They're not exactly equivalent in further versions of the standard, in the example of for (int x = 0; y; z), the scope of x is the for block and is out of scope after the loop ends, whereas with int x; while (y) x it's still in scope after the loop ends.
Another difference is that for interprets missing y as TRUE, whereas while must be supplied with an expression. for (;;) { foo; } is fine, but while() { foo; } isn not.
Source
Author