Printing every 10th result in an alternating ± series
$begingroup$
Problem:
In the following expression 1-2+3-4+5-6 ... -98+99-100
, print result every 10th (10, 20, 30, ...) calculation.
My code:
result = 0
operand = 1
counter = 0
for i in range(1, 101):
result = result + (i * operand)
counter = counter + 1
operand = operand * -1 #Convert between positive and negative number
if counter >= 10:
counter = 0
print(result)
My problem:
I think this code has not good readability. For example, I used * -1 for changing positive and negative number. But it requires math skill(multiplying a negative number) to understand code.
And I don't sure variable name 'counter' and 'operand' is appropriate for this context.
Is there any suggestion?
python python-3.x
$endgroup$
|
show 2 more comments
$begingroup$
Problem:
In the following expression 1-2+3-4+5-6 ... -98+99-100
, print result every 10th (10, 20, 30, ...) calculation.
My code:
result = 0
operand = 1
counter = 0
for i in range(1, 101):
result = result + (i * operand)
counter = counter + 1
operand = operand * -1 #Convert between positive and negative number
if counter >= 10:
counter = 0
print(result)
My problem:
I think this code has not good readability. For example, I used * -1 for changing positive and negative number. But it requires math skill(multiplying a negative number) to understand code.
And I don't sure variable name 'counter' and 'operand' is appropriate for this context.
Is there any suggestion?
python python-3.x
$endgroup$
$begingroup$
Do you need the finalresult
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?
$endgroup$
– Graipher
Dec 10 '18 at 15:29
1
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
1
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20
|
show 2 more comments
$begingroup$
Problem:
In the following expression 1-2+3-4+5-6 ... -98+99-100
, print result every 10th (10, 20, 30, ...) calculation.
My code:
result = 0
operand = 1
counter = 0
for i in range(1, 101):
result = result + (i * operand)
counter = counter + 1
operand = operand * -1 #Convert between positive and negative number
if counter >= 10:
counter = 0
print(result)
My problem:
I think this code has not good readability. For example, I used * -1 for changing positive and negative number. But it requires math skill(multiplying a negative number) to understand code.
And I don't sure variable name 'counter' and 'operand' is appropriate for this context.
Is there any suggestion?
python python-3.x
$endgroup$
Problem:
In the following expression 1-2+3-4+5-6 ... -98+99-100
, print result every 10th (10, 20, 30, ...) calculation.
My code:
result = 0
operand = 1
counter = 0
for i in range(1, 101):
result = result + (i * operand)
counter = counter + 1
operand = operand * -1 #Convert between positive and negative number
if counter >= 10:
counter = 0
print(result)
My problem:
I think this code has not good readability. For example, I used * -1 for changing positive and negative number. But it requires math skill(multiplying a negative number) to understand code.
And I don't sure variable name 'counter' and 'operand' is appropriate for this context.
Is there any suggestion?
python python-3.x
python python-3.x
edited Dec 11 '18 at 5:50
200_success
129k15153415
129k15153415
asked Dec 10 '18 at 14:41
junjun
805
805
$begingroup$
Do you need the finalresult
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?
$endgroup$
– Graipher
Dec 10 '18 at 15:29
1
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
1
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20
|
show 2 more comments
$begingroup$
Do you need the finalresult
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?
$endgroup$
– Graipher
Dec 10 '18 at 15:29
1
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
1
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20
$begingroup$
Do you need the final
result
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?$endgroup$
– Graipher
Dec 10 '18 at 15:29
$begingroup$
Do you need the final
result
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?$endgroup$
– Graipher
Dec 10 '18 at 15:29
1
1
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
1
1
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20
|
show 2 more comments
5 Answers
5
active
oldest
votes
$begingroup$
The first thing you can do to make the sign change obvious is to use operand = -operand
, this way you avoid the need for the multiplication operator. Also changing the operand
name to sign can help.
You also don't need counter
as it will be equal to i
before the test. Just change the test to use the modulo (%
) operator instead of reseting counter
.
And using augmented assignment for result
can lead to a more readable line too:
result = 0
sign = 1
for i in range(1, 101):
result += sign * i
sign = -sign
if i % 10 == 0:
print(result)
Now, this probably need to be made more reusable, this means building a function out of this code and avoiding mixing computation and I/Os:
def alternating_sum(start=1, stop=100, step=10):
result = 0
sign = 1
for i in range(start, stop+1):
result += sign * i
sign = -sign
if i % step == 0:
yield result
Usage being:
for result in alternating_sum(1, 100, 10):
print(result)
Also, depending on the problem at hand, you can leverage the fact that every two numbers add-up to -1
. So every 10 numbers add-up to -5
. If you don't need much genericity, you can simplify the code down to:
def alternating_every_ten(end=100):
reports = end // 10
for i in range(1, reports + 1):
print('After', 10 * i, 'sums, result is', -5 * i)
$endgroup$
$begingroup$
I would recommend writing expressions with a sign variable assign * value
to match the standard method of writing numbers.
$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
add a comment |
$begingroup$
You can get rid of your counter
and directly use i
by using modular arithmetic. i % 10 == 0
is true whenever i
is divisible by 10
.
You can get rid of your operand = operand * -1
by using itertools.cycle
.
from itertools import cycle
result = 0
for i, sign in zip(range(1, 101), cycle([1, -1])):
result += sign * i
if i % 10 == 0:
print(result)
The generation of result
itself would be a lot more concise with a generator comprehension, but this excludes the progress prints:
result = sum(sign * i for i, sign in zip(range(1, 101), cycle([1, -1])))
$endgroup$
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
add a comment |
$begingroup$
instead of doing the +-
by hand, you can use the fact that (-1) ** (i-1) * i for i in range(101)
alternates the values
Further on, you can use itertools.accumulate
and itertools.islice
to take the cumulative sum and select every 10th number
numbers = (int((-1) ** (i-1) * i) for i in range(101))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 10, None, 10)
for i in numbers_10:
print(i)
-5
-10
-15
-20
-25
-30
-35
-40
-45
-50
or alternatively, per 200_success' suggestion:
numbers = (sign * i for sign, i in zip(itertools.cycle((1, -1)), itertools.count(1)))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 9, 100, 10)
$endgroup$
$begingroup$
With this you do not get the final result, though. Maybe with aitertools.tee
of thenumbers
, which you can thensum
, but then it is no longer reporting on the progress...
$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to docum_sum = list(itertools.accumulate(numbers))
ornumbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
$begingroup$
I like this. Personally, I'd write it ascum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums withfor n in islice(cum_sum, 9, 100, 10): print(n)
.
$endgroup$
– 200_success
Dec 11 '18 at 0:11
add a comment |
$begingroup$
I would convert the sign flip into a generator, created via a generator comprehension, recognizing that evens should be negative:
# Integers from 1-100, where evens are negative: 1, -2, 3, -4, 5...
sequence_gen = (i if i % 2 else -i for i in range(1,101))
Equivalent to:
def sequence_gen():
for i in range(1, 101):
if bool(i % 2): # For our purposes this is i % 2 == 1:
yield i
else:
yield -i
Then your code becomes:
result = 0
for index, number in enumerate(sequence_gen):
result += number
if index % 10 == 9: # Note the comparison change by starting at 0
print(result)
Note this is about half way to what Mathias proposed, and can be used in conjunction, the combination being:
def sequence_sums(start, stop, step):
result = 0
seq_gen = (i if i % 2 else -i for i in range(start, stop + 1))
for index, number in enumerate(seq_gen):
result += number
if index % step == step - 1:
yield result
You could even go one further step and make the sequence a parameter:
# iterates through a sequence, printing every step'th sum
def sequence_sums(sequence, step):
result = 0
for index, number in enumerate(sequence):
result += number
if index % step == step - 1:
yield result
Called via:
sequence = (i if i % 2 else -i for i in range(1, 101))
for sum in sequence_sums(sequence, 10):
print(sum)
$endgroup$
1
$begingroup$
Note the comparison change by starting at 0
=>enumerate
takes a second, optional, argument:start
. So you can useenumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
add a comment |
$begingroup$
The other answers are fine. Here is a mathematical analysis of the problem you're trying to solve.
If this code is, for some reason, used in a performance-critical scenario, you can calculate the sum to $m$ in $O(1)$ time.
Notice that:
$$
begin{align}
1-2+3-4+5-6dots m &= -sum_{n=1}^{m}n(-1)^n \
&= sum_{n=1}^{m}n(-1)^{n-1} \
&= frac{1}{4}-frac{1}{4}(-1)^m(2m+1) ; ^*
end{align}
$$
* There was a typo in my original comment.
Because you only want to see every 10th result, we can substitute $m=10u$ where $uinmathbb{Z}$. This is fortunate because for all integers $(-1)^{10u} equiv 1$. Therefore:
$$
begin{align}
frac{1}{4}-frac{1}{4}(-1)^{10u}(20u+1) &= frac{1}{4}-frac{1}{4}(20u+1) \
&= frac{1}{4}-frac{20u+1}{4}\
&= frac{(1-1)-20u}{4} \
&= -5u
end{align}
$$
Look familiar? It results in $-5$, $-10$, $-15$, ...
This fact is obvious from the output, but now knowing the series that produces it, we can calculate the final result for any such $m$ quickly, and every 10th value even easier.
We can avoid computing the exponent $(-1)^m$ because $(-1)^{m} = 1$ for even values of $m$ and $-1$ for odd values.
I'm not as familiar with Python, but here's an example:
def series(m):
alt = 1 if m % 2 == 0 else -1
return int(1/4 - 1/4 * alt * (2 * m + 1))
def series_progress(m):
return -5 * m
m = 134
for i in range(1, m // 10):
print(series_progress(i))
print(series(m))
This avoids the costly computation for the final result. If we just needed the result it would be $O(1)$, but because we give "progress reports" it is more like $lfloorfrac{n}{10}rfloorin O(n)$.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209364%2fprinting-every-10th-result-in-an-alternating-%25c2%25b1-series%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
The first thing you can do to make the sign change obvious is to use operand = -operand
, this way you avoid the need for the multiplication operator. Also changing the operand
name to sign can help.
You also don't need counter
as it will be equal to i
before the test. Just change the test to use the modulo (%
) operator instead of reseting counter
.
And using augmented assignment for result
can lead to a more readable line too:
result = 0
sign = 1
for i in range(1, 101):
result += sign * i
sign = -sign
if i % 10 == 0:
print(result)
Now, this probably need to be made more reusable, this means building a function out of this code and avoiding mixing computation and I/Os:
def alternating_sum(start=1, stop=100, step=10):
result = 0
sign = 1
for i in range(start, stop+1):
result += sign * i
sign = -sign
if i % step == 0:
yield result
Usage being:
for result in alternating_sum(1, 100, 10):
print(result)
Also, depending on the problem at hand, you can leverage the fact that every two numbers add-up to -1
. So every 10 numbers add-up to -5
. If you don't need much genericity, you can simplify the code down to:
def alternating_every_ten(end=100):
reports = end // 10
for i in range(1, reports + 1):
print('After', 10 * i, 'sums, result is', -5 * i)
$endgroup$
$begingroup$
I would recommend writing expressions with a sign variable assign * value
to match the standard method of writing numbers.
$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
add a comment |
$begingroup$
The first thing you can do to make the sign change obvious is to use operand = -operand
, this way you avoid the need for the multiplication operator. Also changing the operand
name to sign can help.
You also don't need counter
as it will be equal to i
before the test. Just change the test to use the modulo (%
) operator instead of reseting counter
.
And using augmented assignment for result
can lead to a more readable line too:
result = 0
sign = 1
for i in range(1, 101):
result += sign * i
sign = -sign
if i % 10 == 0:
print(result)
Now, this probably need to be made more reusable, this means building a function out of this code and avoiding mixing computation and I/Os:
def alternating_sum(start=1, stop=100, step=10):
result = 0
sign = 1
for i in range(start, stop+1):
result += sign * i
sign = -sign
if i % step == 0:
yield result
Usage being:
for result in alternating_sum(1, 100, 10):
print(result)
Also, depending on the problem at hand, you can leverage the fact that every two numbers add-up to -1
. So every 10 numbers add-up to -5
. If you don't need much genericity, you can simplify the code down to:
def alternating_every_ten(end=100):
reports = end // 10
for i in range(1, reports + 1):
print('After', 10 * i, 'sums, result is', -5 * i)
$endgroup$
$begingroup$
I would recommend writing expressions with a sign variable assign * value
to match the standard method of writing numbers.
$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
add a comment |
$begingroup$
The first thing you can do to make the sign change obvious is to use operand = -operand
, this way you avoid the need for the multiplication operator. Also changing the operand
name to sign can help.
You also don't need counter
as it will be equal to i
before the test. Just change the test to use the modulo (%
) operator instead of reseting counter
.
And using augmented assignment for result
can lead to a more readable line too:
result = 0
sign = 1
for i in range(1, 101):
result += sign * i
sign = -sign
if i % 10 == 0:
print(result)
Now, this probably need to be made more reusable, this means building a function out of this code and avoiding mixing computation and I/Os:
def alternating_sum(start=1, stop=100, step=10):
result = 0
sign = 1
for i in range(start, stop+1):
result += sign * i
sign = -sign
if i % step == 0:
yield result
Usage being:
for result in alternating_sum(1, 100, 10):
print(result)
Also, depending on the problem at hand, you can leverage the fact that every two numbers add-up to -1
. So every 10 numbers add-up to -5
. If you don't need much genericity, you can simplify the code down to:
def alternating_every_ten(end=100):
reports = end // 10
for i in range(1, reports + 1):
print('After', 10 * i, 'sums, result is', -5 * i)
$endgroup$
The first thing you can do to make the sign change obvious is to use operand = -operand
, this way you avoid the need for the multiplication operator. Also changing the operand
name to sign can help.
You also don't need counter
as it will be equal to i
before the test. Just change the test to use the modulo (%
) operator instead of reseting counter
.
And using augmented assignment for result
can lead to a more readable line too:
result = 0
sign = 1
for i in range(1, 101):
result += sign * i
sign = -sign
if i % 10 == 0:
print(result)
Now, this probably need to be made more reusable, this means building a function out of this code and avoiding mixing computation and I/Os:
def alternating_sum(start=1, stop=100, step=10):
result = 0
sign = 1
for i in range(start, stop+1):
result += sign * i
sign = -sign
if i % step == 0:
yield result
Usage being:
for result in alternating_sum(1, 100, 10):
print(result)
Also, depending on the problem at hand, you can leverage the fact that every two numbers add-up to -1
. So every 10 numbers add-up to -5
. If you don't need much genericity, you can simplify the code down to:
def alternating_every_ten(end=100):
reports = end // 10
for i in range(1, reports + 1):
print('After', 10 * i, 'sums, result is', -5 * i)
edited Dec 10 '18 at 20:11
answered Dec 10 '18 at 15:19
Mathias EttingerMathias Ettinger
24.4k33184
24.4k33184
$begingroup$
I would recommend writing expressions with a sign variable assign * value
to match the standard method of writing numbers.
$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
add a comment |
$begingroup$
I would recommend writing expressions with a sign variable assign * value
to match the standard method of writing numbers.
$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
$begingroup$
I would recommend writing expressions with a sign variable as
sign * value
to match the standard method of writing numbers.$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
I would recommend writing expressions with a sign variable as
sign * value
to match the standard method of writing numbers.$endgroup$
– Apollys
Dec 10 '18 at 18:41
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
$begingroup$
@Apollys Right, fixed.
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 20:11
add a comment |
$begingroup$
You can get rid of your counter
and directly use i
by using modular arithmetic. i % 10 == 0
is true whenever i
is divisible by 10
.
You can get rid of your operand = operand * -1
by using itertools.cycle
.
from itertools import cycle
result = 0
for i, sign in zip(range(1, 101), cycle([1, -1])):
result += sign * i
if i % 10 == 0:
print(result)
The generation of result
itself would be a lot more concise with a generator comprehension, but this excludes the progress prints:
result = sum(sign * i for i, sign in zip(range(1, 101), cycle([1, -1])))
$endgroup$
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
add a comment |
$begingroup$
You can get rid of your counter
and directly use i
by using modular arithmetic. i % 10 == 0
is true whenever i
is divisible by 10
.
You can get rid of your operand = operand * -1
by using itertools.cycle
.
from itertools import cycle
result = 0
for i, sign in zip(range(1, 101), cycle([1, -1])):
result += sign * i
if i % 10 == 0:
print(result)
The generation of result
itself would be a lot more concise with a generator comprehension, but this excludes the progress prints:
result = sum(sign * i for i, sign in zip(range(1, 101), cycle([1, -1])))
$endgroup$
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
add a comment |
$begingroup$
You can get rid of your counter
and directly use i
by using modular arithmetic. i % 10 == 0
is true whenever i
is divisible by 10
.
You can get rid of your operand = operand * -1
by using itertools.cycle
.
from itertools import cycle
result = 0
for i, sign in zip(range(1, 101), cycle([1, -1])):
result += sign * i
if i % 10 == 0:
print(result)
The generation of result
itself would be a lot more concise with a generator comprehension, but this excludes the progress prints:
result = sum(sign * i for i, sign in zip(range(1, 101), cycle([1, -1])))
$endgroup$
You can get rid of your counter
and directly use i
by using modular arithmetic. i % 10 == 0
is true whenever i
is divisible by 10
.
You can get rid of your operand = operand * -1
by using itertools.cycle
.
from itertools import cycle
result = 0
for i, sign in zip(range(1, 101), cycle([1, -1])):
result += sign * i
if i % 10 == 0:
print(result)
The generation of result
itself would be a lot more concise with a generator comprehension, but this excludes the progress prints:
result = sum(sign * i for i, sign in zip(range(1, 101), cycle([1, -1])))
answered Dec 10 '18 at 15:12
GraipherGraipher
24.3k53586
24.3k53586
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
add a comment |
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
@MathiasEttinger: It seems like MaartenFabre is already going in that direction in their answer.
$endgroup$
– Graipher
Dec 10 '18 at 15:25
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
$begingroup$
Yep, saw that after the comment
$endgroup$
– Mathias Ettinger
Dec 10 '18 at 15:28
add a comment |
$begingroup$
instead of doing the +-
by hand, you can use the fact that (-1) ** (i-1) * i for i in range(101)
alternates the values
Further on, you can use itertools.accumulate
and itertools.islice
to take the cumulative sum and select every 10th number
numbers = (int((-1) ** (i-1) * i) for i in range(101))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 10, None, 10)
for i in numbers_10:
print(i)
-5
-10
-15
-20
-25
-30
-35
-40
-45
-50
or alternatively, per 200_success' suggestion:
numbers = (sign * i for sign, i in zip(itertools.cycle((1, -1)), itertools.count(1)))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 9, 100, 10)
$endgroup$
$begingroup$
With this you do not get the final result, though. Maybe with aitertools.tee
of thenumbers
, which you can thensum
, but then it is no longer reporting on the progress...
$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to docum_sum = list(itertools.accumulate(numbers))
ornumbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
$begingroup$
I like this. Personally, I'd write it ascum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums withfor n in islice(cum_sum, 9, 100, 10): print(n)
.
$endgroup$
– 200_success
Dec 11 '18 at 0:11
add a comment |
$begingroup$
instead of doing the +-
by hand, you can use the fact that (-1) ** (i-1) * i for i in range(101)
alternates the values
Further on, you can use itertools.accumulate
and itertools.islice
to take the cumulative sum and select every 10th number
numbers = (int((-1) ** (i-1) * i) for i in range(101))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 10, None, 10)
for i in numbers_10:
print(i)
-5
-10
-15
-20
-25
-30
-35
-40
-45
-50
or alternatively, per 200_success' suggestion:
numbers = (sign * i for sign, i in zip(itertools.cycle((1, -1)), itertools.count(1)))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 9, 100, 10)
$endgroup$
$begingroup$
With this you do not get the final result, though. Maybe with aitertools.tee
of thenumbers
, which you can thensum
, but then it is no longer reporting on the progress...
$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to docum_sum = list(itertools.accumulate(numbers))
ornumbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
$begingroup$
I like this. Personally, I'd write it ascum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums withfor n in islice(cum_sum, 9, 100, 10): print(n)
.
$endgroup$
– 200_success
Dec 11 '18 at 0:11
add a comment |
$begingroup$
instead of doing the +-
by hand, you can use the fact that (-1) ** (i-1) * i for i in range(101)
alternates the values
Further on, you can use itertools.accumulate
and itertools.islice
to take the cumulative sum and select every 10th number
numbers = (int((-1) ** (i-1) * i) for i in range(101))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 10, None, 10)
for i in numbers_10:
print(i)
-5
-10
-15
-20
-25
-30
-35
-40
-45
-50
or alternatively, per 200_success' suggestion:
numbers = (sign * i for sign, i in zip(itertools.cycle((1, -1)), itertools.count(1)))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 9, 100, 10)
$endgroup$
instead of doing the +-
by hand, you can use the fact that (-1) ** (i-1) * i for i in range(101)
alternates the values
Further on, you can use itertools.accumulate
and itertools.islice
to take the cumulative sum and select every 10th number
numbers = (int((-1) ** (i-1) * i) for i in range(101))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 10, None, 10)
for i in numbers_10:
print(i)
-5
-10
-15
-20
-25
-30
-35
-40
-45
-50
or alternatively, per 200_success' suggestion:
numbers = (sign * i for sign, i in zip(itertools.cycle((1, -1)), itertools.count(1)))
cum_sum = itertools.accumulate(numbers)
numbers_10 = itertools.islice(cum_sum, 9, 100, 10)
edited Dec 11 '18 at 9:08
answered Dec 10 '18 at 15:19
Maarten FabréMaarten Fabré
4,664417
4,664417
$begingroup$
With this you do not get the final result, though. Maybe with aitertools.tee
of thenumbers
, which you can thensum
, but then it is no longer reporting on the progress...
$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to docum_sum = list(itertools.accumulate(numbers))
ornumbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
$begingroup$
I like this. Personally, I'd write it ascum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums withfor n in islice(cum_sum, 9, 100, 10): print(n)
.
$endgroup$
– 200_success
Dec 11 '18 at 0:11
add a comment |
$begingroup$
With this you do not get the final result, though. Maybe with aitertools.tee
of thenumbers
, which you can thensum
, but then it is no longer reporting on the progress...
$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to docum_sum = list(itertools.accumulate(numbers))
ornumbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
$begingroup$
I like this. Personally, I'd write it ascum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums withfor n in islice(cum_sum, 9, 100, 10): print(n)
.
$endgroup$
– 200_success
Dec 11 '18 at 0:11
$begingroup$
With this you do not get the final result, though. Maybe with a
itertools.tee
of the numbers
, which you can then sum
, but then it is no longer reporting on the progress...$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
With this you do not get the final result, though. Maybe with a
itertools.tee
of the numbers
, which you can then sum
, but then it is no longer reporting on the progress...$endgroup$
– Graipher
Dec 10 '18 at 15:24
$begingroup$
what do you mean with the final result? If needed, you need to do
cum_sum = list(itertools.accumulate(numbers))
or numbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
$begingroup$
what do you mean with the final result? If needed, you need to do
cum_sum = list(itertools.accumulate(numbers))
or numbers = [int((-1) ** (i-1) * i) for i in range(101)]
$endgroup$
– Maarten Fabré
Dec 10 '18 at 15:37
2
2
$begingroup$
I like this. Personally, I'd write it as
cum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums with for n in islice(cum_sum, 9, 100, 10): print(n)
.$endgroup$
– 200_success
Dec 11 '18 at 0:11
$begingroup$
I like this. Personally, I'd write it as
cum_sum = accumulate(sign * n for sign, n in zip(cycle((+1, -1)), count()))
to more elegantly express the idea of an infinite series, then extract just the relevant partial sums with for n in islice(cum_sum, 9, 100, 10): print(n)
.$endgroup$
– 200_success
Dec 11 '18 at 0:11
add a comment |
$begingroup$
I would convert the sign flip into a generator, created via a generator comprehension, recognizing that evens should be negative:
# Integers from 1-100, where evens are negative: 1, -2, 3, -4, 5...
sequence_gen = (i if i % 2 else -i for i in range(1,101))
Equivalent to:
def sequence_gen():
for i in range(1, 101):
if bool(i % 2): # For our purposes this is i % 2 == 1:
yield i
else:
yield -i
Then your code becomes:
result = 0
for index, number in enumerate(sequence_gen):
result += number
if index % 10 == 9: # Note the comparison change by starting at 0
print(result)
Note this is about half way to what Mathias proposed, and can be used in conjunction, the combination being:
def sequence_sums(start, stop, step):
result = 0
seq_gen = (i if i % 2 else -i for i in range(start, stop + 1))
for index, number in enumerate(seq_gen):
result += number
if index % step == step - 1:
yield result
You could even go one further step and make the sequence a parameter:
# iterates through a sequence, printing every step'th sum
def sequence_sums(sequence, step):
result = 0
for index, number in enumerate(sequence):
result += number
if index % step == step - 1:
yield result
Called via:
sequence = (i if i % 2 else -i for i in range(1, 101))
for sum in sequence_sums(sequence, 10):
print(sum)
$endgroup$
1
$begingroup$
Note the comparison change by starting at 0
=>enumerate
takes a second, optional, argument:start
. So you can useenumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
add a comment |
$begingroup$
I would convert the sign flip into a generator, created via a generator comprehension, recognizing that evens should be negative:
# Integers from 1-100, where evens are negative: 1, -2, 3, -4, 5...
sequence_gen = (i if i % 2 else -i for i in range(1,101))
Equivalent to:
def sequence_gen():
for i in range(1, 101):
if bool(i % 2): # For our purposes this is i % 2 == 1:
yield i
else:
yield -i
Then your code becomes:
result = 0
for index, number in enumerate(sequence_gen):
result += number
if index % 10 == 9: # Note the comparison change by starting at 0
print(result)
Note this is about half way to what Mathias proposed, and can be used in conjunction, the combination being:
def sequence_sums(start, stop, step):
result = 0
seq_gen = (i if i % 2 else -i for i in range(start, stop + 1))
for index, number in enumerate(seq_gen):
result += number
if index % step == step - 1:
yield result
You could even go one further step and make the sequence a parameter:
# iterates through a sequence, printing every step'th sum
def sequence_sums(sequence, step):
result = 0
for index, number in enumerate(sequence):
result += number
if index % step == step - 1:
yield result
Called via:
sequence = (i if i % 2 else -i for i in range(1, 101))
for sum in sequence_sums(sequence, 10):
print(sum)
$endgroup$
1
$begingroup$
Note the comparison change by starting at 0
=>enumerate
takes a second, optional, argument:start
. So you can useenumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
add a comment |
$begingroup$
I would convert the sign flip into a generator, created via a generator comprehension, recognizing that evens should be negative:
# Integers from 1-100, where evens are negative: 1, -2, 3, -4, 5...
sequence_gen = (i if i % 2 else -i for i in range(1,101))
Equivalent to:
def sequence_gen():
for i in range(1, 101):
if bool(i % 2): # For our purposes this is i % 2 == 1:
yield i
else:
yield -i
Then your code becomes:
result = 0
for index, number in enumerate(sequence_gen):
result += number
if index % 10 == 9: # Note the comparison change by starting at 0
print(result)
Note this is about half way to what Mathias proposed, and can be used in conjunction, the combination being:
def sequence_sums(start, stop, step):
result = 0
seq_gen = (i if i % 2 else -i for i in range(start, stop + 1))
for index, number in enumerate(seq_gen):
result += number
if index % step == step - 1:
yield result
You could even go one further step and make the sequence a parameter:
# iterates through a sequence, printing every step'th sum
def sequence_sums(sequence, step):
result = 0
for index, number in enumerate(sequence):
result += number
if index % step == step - 1:
yield result
Called via:
sequence = (i if i % 2 else -i for i in range(1, 101))
for sum in sequence_sums(sequence, 10):
print(sum)
$endgroup$
I would convert the sign flip into a generator, created via a generator comprehension, recognizing that evens should be negative:
# Integers from 1-100, where evens are negative: 1, -2, 3, -4, 5...
sequence_gen = (i if i % 2 else -i for i in range(1,101))
Equivalent to:
def sequence_gen():
for i in range(1, 101):
if bool(i % 2): # For our purposes this is i % 2 == 1:
yield i
else:
yield -i
Then your code becomes:
result = 0
for index, number in enumerate(sequence_gen):
result += number
if index % 10 == 9: # Note the comparison change by starting at 0
print(result)
Note this is about half way to what Mathias proposed, and can be used in conjunction, the combination being:
def sequence_sums(start, stop, step):
result = 0
seq_gen = (i if i % 2 else -i for i in range(start, stop + 1))
for index, number in enumerate(seq_gen):
result += number
if index % step == step - 1:
yield result
You could even go one further step and make the sequence a parameter:
# iterates through a sequence, printing every step'th sum
def sequence_sums(sequence, step):
result = 0
for index, number in enumerate(sequence):
result += number
if index % step == step - 1:
yield result
Called via:
sequence = (i if i % 2 else -i for i in range(1, 101))
for sum in sequence_sums(sequence, 10):
print(sum)
answered Dec 10 '18 at 23:22
TemporalWolfTemporalWolf
25427
25427
1
$begingroup$
Note the comparison change by starting at 0
=>enumerate
takes a second, optional, argument:start
. So you can useenumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
add a comment |
1
$begingroup$
Note the comparison change by starting at 0
=>enumerate
takes a second, optional, argument:start
. So you can useenumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
1
1
$begingroup$
Note the comparison change by starting at 0
=> enumerate
takes a second, optional, argument: start
. So you can use enumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
$begingroup$
Note the comparison change by starting at 0
=> enumerate
takes a second, optional, argument: start
. So you can use enumerate(sequence, 1)
and keep the usual comparison of the modulo to 0.$endgroup$
– Mathias Ettinger
Dec 11 '18 at 8:00
add a comment |
$begingroup$
The other answers are fine. Here is a mathematical analysis of the problem you're trying to solve.
If this code is, for some reason, used in a performance-critical scenario, you can calculate the sum to $m$ in $O(1)$ time.
Notice that:
$$
begin{align}
1-2+3-4+5-6dots m &= -sum_{n=1}^{m}n(-1)^n \
&= sum_{n=1}^{m}n(-1)^{n-1} \
&= frac{1}{4}-frac{1}{4}(-1)^m(2m+1) ; ^*
end{align}
$$
* There was a typo in my original comment.
Because you only want to see every 10th result, we can substitute $m=10u$ where $uinmathbb{Z}$. This is fortunate because for all integers $(-1)^{10u} equiv 1$. Therefore:
$$
begin{align}
frac{1}{4}-frac{1}{4}(-1)^{10u}(20u+1) &= frac{1}{4}-frac{1}{4}(20u+1) \
&= frac{1}{4}-frac{20u+1}{4}\
&= frac{(1-1)-20u}{4} \
&= -5u
end{align}
$$
Look familiar? It results in $-5$, $-10$, $-15$, ...
This fact is obvious from the output, but now knowing the series that produces it, we can calculate the final result for any such $m$ quickly, and every 10th value even easier.
We can avoid computing the exponent $(-1)^m$ because $(-1)^{m} = 1$ for even values of $m$ and $-1$ for odd values.
I'm not as familiar with Python, but here's an example:
def series(m):
alt = 1 if m % 2 == 0 else -1
return int(1/4 - 1/4 * alt * (2 * m + 1))
def series_progress(m):
return -5 * m
m = 134
for i in range(1, m // 10):
print(series_progress(i))
print(series(m))
This avoids the costly computation for the final result. If we just needed the result it would be $O(1)$, but because we give "progress reports" it is more like $lfloorfrac{n}{10}rfloorin O(n)$.
$endgroup$
add a comment |
$begingroup$
The other answers are fine. Here is a mathematical analysis of the problem you're trying to solve.
If this code is, for some reason, used in a performance-critical scenario, you can calculate the sum to $m$ in $O(1)$ time.
Notice that:
$$
begin{align}
1-2+3-4+5-6dots m &= -sum_{n=1}^{m}n(-1)^n \
&= sum_{n=1}^{m}n(-1)^{n-1} \
&= frac{1}{4}-frac{1}{4}(-1)^m(2m+1) ; ^*
end{align}
$$
* There was a typo in my original comment.
Because you only want to see every 10th result, we can substitute $m=10u$ where $uinmathbb{Z}$. This is fortunate because for all integers $(-1)^{10u} equiv 1$. Therefore:
$$
begin{align}
frac{1}{4}-frac{1}{4}(-1)^{10u}(20u+1) &= frac{1}{4}-frac{1}{4}(20u+1) \
&= frac{1}{4}-frac{20u+1}{4}\
&= frac{(1-1)-20u}{4} \
&= -5u
end{align}
$$
Look familiar? It results in $-5$, $-10$, $-15$, ...
This fact is obvious from the output, but now knowing the series that produces it, we can calculate the final result for any such $m$ quickly, and every 10th value even easier.
We can avoid computing the exponent $(-1)^m$ because $(-1)^{m} = 1$ for even values of $m$ and $-1$ for odd values.
I'm not as familiar with Python, but here's an example:
def series(m):
alt = 1 if m % 2 == 0 else -1
return int(1/4 - 1/4 * alt * (2 * m + 1))
def series_progress(m):
return -5 * m
m = 134
for i in range(1, m // 10):
print(series_progress(i))
print(series(m))
This avoids the costly computation for the final result. If we just needed the result it would be $O(1)$, but because we give "progress reports" it is more like $lfloorfrac{n}{10}rfloorin O(n)$.
$endgroup$
add a comment |
$begingroup$
The other answers are fine. Here is a mathematical analysis of the problem you're trying to solve.
If this code is, for some reason, used in a performance-critical scenario, you can calculate the sum to $m$ in $O(1)$ time.
Notice that:
$$
begin{align}
1-2+3-4+5-6dots m &= -sum_{n=1}^{m}n(-1)^n \
&= sum_{n=1}^{m}n(-1)^{n-1} \
&= frac{1}{4}-frac{1}{4}(-1)^m(2m+1) ; ^*
end{align}
$$
* There was a typo in my original comment.
Because you only want to see every 10th result, we can substitute $m=10u$ where $uinmathbb{Z}$. This is fortunate because for all integers $(-1)^{10u} equiv 1$. Therefore:
$$
begin{align}
frac{1}{4}-frac{1}{4}(-1)^{10u}(20u+1) &= frac{1}{4}-frac{1}{4}(20u+1) \
&= frac{1}{4}-frac{20u+1}{4}\
&= frac{(1-1)-20u}{4} \
&= -5u
end{align}
$$
Look familiar? It results in $-5$, $-10$, $-15$, ...
This fact is obvious from the output, but now knowing the series that produces it, we can calculate the final result for any such $m$ quickly, and every 10th value even easier.
We can avoid computing the exponent $(-1)^m$ because $(-1)^{m} = 1$ for even values of $m$ and $-1$ for odd values.
I'm not as familiar with Python, but here's an example:
def series(m):
alt = 1 if m % 2 == 0 else -1
return int(1/4 - 1/4 * alt * (2 * m + 1))
def series_progress(m):
return -5 * m
m = 134
for i in range(1, m // 10):
print(series_progress(i))
print(series(m))
This avoids the costly computation for the final result. If we just needed the result it would be $O(1)$, but because we give "progress reports" it is more like $lfloorfrac{n}{10}rfloorin O(n)$.
$endgroup$
The other answers are fine. Here is a mathematical analysis of the problem you're trying to solve.
If this code is, for some reason, used in a performance-critical scenario, you can calculate the sum to $m$ in $O(1)$ time.
Notice that:
$$
begin{align}
1-2+3-4+5-6dots m &= -sum_{n=1}^{m}n(-1)^n \
&= sum_{n=1}^{m}n(-1)^{n-1} \
&= frac{1}{4}-frac{1}{4}(-1)^m(2m+1) ; ^*
end{align}
$$
* There was a typo in my original comment.
Because you only want to see every 10th result, we can substitute $m=10u$ where $uinmathbb{Z}$. This is fortunate because for all integers $(-1)^{10u} equiv 1$. Therefore:
$$
begin{align}
frac{1}{4}-frac{1}{4}(-1)^{10u}(20u+1) &= frac{1}{4}-frac{1}{4}(20u+1) \
&= frac{1}{4}-frac{20u+1}{4}\
&= frac{(1-1)-20u}{4} \
&= -5u
end{align}
$$
Look familiar? It results in $-5$, $-10$, $-15$, ...
This fact is obvious from the output, but now knowing the series that produces it, we can calculate the final result for any such $m$ quickly, and every 10th value even easier.
We can avoid computing the exponent $(-1)^m$ because $(-1)^{m} = 1$ for even values of $m$ and $-1$ for odd values.
I'm not as familiar with Python, but here's an example:
def series(m):
alt = 1 if m % 2 == 0 else -1
return int(1/4 - 1/4 * alt * (2 * m + 1))
def series_progress(m):
return -5 * m
m = 134
for i in range(1, m // 10):
print(series_progress(i))
print(series(m))
This avoids the costly computation for the final result. If we just needed the result it would be $O(1)$, but because we give "progress reports" it is more like $lfloorfrac{n}{10}rfloorin O(n)$.
edited Dec 11 '18 at 23:13
answered Dec 11 '18 at 23:05
esoteesote
2,6761935
2,6761935
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209364%2fprinting-every-10th-result-in-an-alternating-%25c2%25b1-series%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Do you need the final
result
of the whole sum and just want to report progress as the summing is going on, or do you want the sum of only every 10th element and also print progress?$endgroup$
– Graipher
Dec 10 '18 at 15:29
1
$begingroup$
Maybe I'm missing something, but isn't the alternating sum you want $$-sum_{n=1}^{m} n (-1)^n equiv -frac{1}{4}-frac{1}{4}(-1)^m (2m+1)$$ And then you can substitute m = 10n or whatever value you need. Far faster than looping.
$endgroup$
– esote
Dec 11 '18 at 1:35
$begingroup$
@Graipher I want to report progress as the summing is going on. but original question is not clear. So i think it should be interpreted like this.
$endgroup$
– jun
Dec 11 '18 at 1:50
$begingroup$
@esote this seems like the start of an answer
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 21:59
1
$begingroup$
@esote Mathematical analysis of a problem in order to reduce code complexity are usually well received.
$endgroup$
– Mathias Ettinger
Dec 11 '18 at 22:20