More elegant method to continuously divide

I have written this code to continuously divide a number, however it’s neither elegant nor extendable, if for instance I wanted a much larger array.

w = 32;
q = Array.fill(6, {|i| w/[1, 2, 4, 8, 16, 32 ].at(i)}).asInteger;

My initial approach was to try to keep dividing the number by 2, though I couldn’t find a way to do this with a variable.

642.collect{|i| 32 / 2.pow(i) }

like that?

1 Like
w / (2 ** (0..5))

Replace 5 with a larger number, if desired. Note that this works because of array expansion and (0..5) == [0, 1, 2, 3, 4, 5].

1 Like

Both of these are really nice, concise solutions. Thank you for sharing them. Much appreciated.

This is worth thinking through, though… if you want to do something with the variable but it isn’t evident how to do it, that’s a bit of programming vocabulary that would be worth developing.

(Oh, btw, I notice that you would like it to be extendable, but there’s also asInteger which does impose a lower limit. I’ll drop asInteger here.)

The obvious first attempt omits the w/1 term.

(
var w = 32;
q = Array.fill(6, { |i|
	w = w / 2;
});
)

-> [ 16.0, 8.0, 4.0, 2.0, 1.0, 0.5 ]

I assume this was the problem that led you to abandon the “variable” approach.

The problem with that is that it’s dividing first, then taking the result of the division as the array element. To get the pre-division result, you need to save it, update the state, and then return the saved, previous state.

(
var w = 32;
q = Array.fill(6, {
	var saveW = w;
	w = w / 2;
	saveW
});
)

-> [ 32, 16.0, 8.0, 4.0, 2.0, 1.0 ]

… which explains what’s going on, but is a bit ugly. The firstArg math operator could tighten it down, at the expense of readers of the code wondering “what is firstArg?”

(
var w = 32;
q = Array.fill(6, {
	w firstArg: (w = w / 2)
});
)

(Shorter syntax would be w <! (w = w / 2) but at that point we’ve pretty much abandoned any pretense of readability… I would have written this 15 years ago but now I think readability is more important than “looky how many punctuation marks I can cram onto one line.”)

Alternately, a routine allows you to return a value at any time, not only at the end of the function:

(
r = Routine {
	var w = 32;
	loop {
		w.yield;  // "pre-" result
		w = w / 2;
	}
};

r.nextN(6)
)

Lastly, Pgeom(32, 0.5, inf).asStream.nextN(6).

hjh

Hi Jamshark,

That is a fascinating post - or pretty much mini-tutorial - thank you so much. I like this as a principle:

if you want to do something with the variable but it isn’t evident how to do it, that’s a bit of programming vocabulary that would be worth developing.

It all makes sense except for the “firstArg” part, which isn’t in the documentation, but I think I get it; it’s returning the value of w before the division has occurred.

This has helped clarify a lot for me, thank you.