set myVar to "000999999"
set myNum to (myVar as number) + 1
set newNum to {}
repeat until myNum < 1
set beginning of newNum to myNum mod 10 as integer
set myNum to myNum div 10
end repeat
repeat (length of myVar) - (length of newNum) times
set beginning of newNum to 0
end repeat
set {oldTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ""}
set newVar to newNum as string
set AppleScript's text item delimiters to oldTID
return newVar
EDIT: I had an error in my previously code. When you have the number as in this example the number of leading zero’s would remain three while it should be 2. That’s been fixed now.
EDIT 2: Nigel indicated a safety leak when newNum is coerced into a string when the delimiters are not set to “”. Now the delimiters are temporarily set to “” before the coercion takes place and then set the delimiters back to it’s previous value.
Here is another take, which may be less readable, but faster in loops with over 1000 iterations.
property zeroes : "0000000000" -- 10 digits should be enough for most purposes.
# This solution only works for numbers smaller than 2^29 which is 536 870 912 decimal.
# and you will of course have to add a considerable number of zeroes.
set myVar to "000999999"
set myVar to incrementZ(myVar)
on incrementZ(zeroedNum)
tell zeroedNum to set {zeroFill, numlen} to {text 1 thru (length of it) of zeroes, (length of it)}
tell (a reference to text item delimiters) to set {tids, contents of it} to {contents of it, ""}
tell (((zeroedNum as number) + 1) as text) to set newnum to text 1 thru (numlen - (length of it)) of zeroFill & it
tell (a reference to text item delimiters) to set contents of it to tids
return newnum
end incrementZ
Well we both have bugs in our solutions. While mine will break down when an real loses it’s precision (higher than 1E+22), yours will break down when integer are notated exponential (2 ^ 29 and higher). McUser’s example break when the initial question number is given, that’s how I find out.
Because the given number is an string the number can even exceed a reals presentation of a number. So therefore I post a third solution. This solution can contain unpronounceable figures but the drawback it’s also the slowest version. Just an example number that can’t be handled by AppleScript (real loses precision here) so My previous as McUser’s solution will break on the following number.
set myVar to "0033620340000000000000000000000000000000000000000000000000000000000000000001"
set newNum to ""
set sum to 1 --this will increment the value
repeat with symbol from (count myVar) to 1 by -1
set sum to (character symbol of myVar) + sum
set newNum to ((sum mod 10) as string) & newNum
set sum to sum div 10
if sum = 0 then
if symbol is not 1 then set newNum to text 1 thru (symbol - 1) of myVar & newNum
exit repeat
end if
end repeat
if sum is 1 then
set newNum to "1" & newNum
else
repeat (length of myVar) - (length of newNum) times
set newNum to "0" & newNum
end repeat
end if
return newNum
edit: A more efficient way. When there is no remainder we can quit processing an simply copy everything from the left of our current symbol to the new number.
edit 2: A simplified version that doesn’t need any help from a list only remains in class string. This makes processing the number’s boundaries equal to the boundaries of the given value (length of the string).
It was most interesting to read about the limitations. I really only assumed the integer to be within the magnitude 10^9.
( I really thought a real lost precision at 1E15, at least that was what it was the last time I investigated it. Edit
And it still holds true. Maybe you are putting something else in the precisison than I do, because I mean how many digits you can safely assume are correct.
(*
Accuracy: J is the number of significan bits in the mantissa of a real.
0.30103 is the number of significant digits in a decimal number. (The constant 0.30103 is log10 2
(Source: Meeus astronomical algorithms, first edition p. 17. rewritten from Basic by me.)
*)
set x to 1
set j to 0
repeat
set x to x * 2
if (x + 1) = x then exit repeat
set j to j + 1
end repeat
log "" & (j * 0.30103) div 1
I have added a comment to my version, that makes the assumption about what range it is supposed to work within clear, and that the user can’t expect the solution to work for integers above 2^29.
Edit
The internal precisison actually holds for numbers up to 2^52 which is 4 503 599 627 370 496 (but the numbers are represented as reals from 2^29 onwards, (536 870 912 decimal) which is really the only sane way to treat such big numbers.)
You’re right, i did something wrong from my 2 ^ 53 to 10E+n notation. Double (or float) can hold precise values until 2 ^ 53 which is a lot bigger than (2 ^ 29) -1.
My understanding is that sum can’t be used as a variable name.
I guess that it’s due to Satimage which is available on my machine.
I liked the first script because it was possible to use it with an increment greater than 1 ( I tested with 19 )
At this time I didn’t find how edit the new one to do that.
Yvan KOENIG (VALLAURIS, France) lundi 10 mars 2014 20:52:06
I just cut it at 2^52, because that is the easiest limit to set up.
Now this was interesting, and if you really want to go higher, then you can by all means somehow do a mod (2^29) and div (2^29) to represent the parts as integers, (with leading zeroes), but when using numbers as big as that for representing series or models of stuff, or for implementing a kind of double Dewey system for that matter, I start to feel that it will be more appropriate to design a dedicated data structure for it, consisting of multiple integers, that logically represent “something”.
thanks for all of your input and I must admit to getting lost in some of the maths, but I had an idea on the way home from work which I think will cover what I want to do simply:
set myVar to "0033620340000"
set leadingZeros to ""
repeat (count of characters of myVar) times
set leadingZeros to leadingZeros & "0"
end repeat
repeat 15 times
set tmpVar to do shell script "x=" & myVar & "; y=1; echo `expr $x + $y`"
set myVar to text -(count of characters of myVar) thru -1 of (leadingZeros & tmpVar)
display dialog myVar
end repeat
This seems similar to DJ’s second script, but is simpler:
set myVar to "0033620340000"
set incrementAmount to 1 -- Normally 1 for "increment", but larger integer values also work.
set myVar to incrementNumericStr(myVar, incrementAmount)
to incrementNumericStr(numStr, incrementAmount)
set numStrDigits to numStr's characters
set s to incrementAmount
repeat with i from (count numStrDigits) to 1 by -1
set s to s + (item i of numStrDigits)
set item i of numStrDigits to s mod 10
set s to s div 10
if (s = 0) then exit repeat
end repeat
if (s > 0) then error "Overflow in incrementNumericStr(). Incrementing " & numStr & " by " & incrementAmount & " would increase the number of digits."
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ""
set newNumStr to numStrDigits as text
set AppleScript's text item delimiters to astid
return newNumStr
end incrementNumericStr
I always test my code on a clean machine, so I guess it is an scripting addition that causes the problem. Thanks for pointing it out.
I think, something I learned from C many years ago, that when you have an certain type of given value, you should stick what that sort of type object. I mean especially when it is with numbers. I think that the most know error caused by this is the cluster spacecraft launch that failed due to an integer overflow. You can even use 20 integers to allow higher values but it’s still limited while using an string and processing the string you are only limited to the same boundaries as the given string (it’s length). I know it’s a lot of processing and most will consider this as a lot of overhead but still banks today does process numbers this way.
We don’t know how big integer values get, you do know, but using a do shell script has the same boundaries as my first example. meaning that integer values become 2 ^ 53 (2 ^ 63 for bash) or larger it will lose it’s precision.
First of all, let me say that when I wanted to break up the number, then it was because I assumed the number to be used in a series for catalouging something, and not say a “running-number” used to say; indexing a transaction.
As such, I saw that the number be used more as a symbolic number to denote, some kind of order, and then I felt, and still feel that it is better to use another datastructure than an integer to represent that “model-object”.
By the way: the Ariadne incident, (we should all be happy for the fact that there weren’t humans on board) due to using a library built for 32-bit on a 64 bit platform actually is something that I (like many others) have learned something from, when it comes to having old software run on a new platform.
Back to topic: I think Nigel’s solution is the best when done in AppleScript since he throws an error, I have just tried Nik’s expr, and that works with large integers, and is probably the best solution if the numbers that needs to be incremented is more likely to be above the 530 million magnitude, there is however a certain price to pay with regards to speed.
I haven’t tried this, but maybe the seq command are up for the job, and can deliver faster, but then again: you have to precompute the end value.
Why not make a composite solution Nik, where you implement your do shell script solution where Nigel’s throws an error?
The main difference between Nigel’s version and mine is that I’ll make “99” + 1 just into “100” while Nigel’s version will throw an error. However Nigel’s script, like mine, can handle larger numbers than bash, so there is still gap in best of both worlds. To make Nigel’s script work like mine you can simply add a 1 to the beginning of the string when s is not 0 instead of throwing an error, but that only works when you increment the value by 1.
Do you know the reason? If you take a look at Nik’s script you’ll see that Nik doesn’t want the error to be thrown for that particular reason.
It’s an 64 bit integer limitation but it’s still an limitation. But if the TS is okay with these boundaries, or if the given number is a 64 bit integer (which I doubt because it has leading zeros), then the problem is solved. Still I think it’s good to show a version like mine and Nigel that has no boundaries whatsoever, only the length of an string or list meaning the same boundaries as the given value type.