Using Floor/Ceil to round decimals to integer of 5 - python

I have been using the code below to handily round to 1dp where I needed the .5s to round upwards, e.g. I wanted a value such as 36.25 to round to 36.3, not 36.2.
def my_round(n, ndigits=1):
try:
part = n * 10 ** ndigits
delta = part - int(part)
# always round "away from 0"
if delta >= 0.5 or -0.5 < delta <= 0:
part = math.ceil(part)
else:
part = math.floor(part)
val = part/(10 ** ndigits)
except ValueError:
val = np.nan
return val
I now need to round a different decimal column in a df to the nearest 5 whole numbers. Can anyone help suggest how I can tweak my original code above to do this? I need, for example, a value such as 702.5000 rounding to 705. Using the normal Round() it obviously goes to 700. In the example, all other normal rounding rules should apply e.g.
702.222 to 700,
707.466 to 705,
703.021 to 705

To round to a certain number of decimal places, use this:
def my_round(x: float, round_to: float = 5, dp: int = 0) -> float:
round_to *= 10**dp
x *= 10**dp
return ((x + round_to / 2) // round_to * round_to) / 10**dp
Testing it:
values = [702.500, 702.222, 707.466, 703.021]
targets = [705., 700., 705., 705.]
assert [my_round(x, 5, 0) for x in values] == targets
assert my_round(3.25, 0.1, 1) == 36.3

def my_round(n):
lower = (n//5)*5;
upper = lower+5;
if (n-lower)<(upper-n):
return int(lower)
return int(upper)
print(my_round(703.021))
The above program tries to find out the proper multiple of 5 before and after the given number.
Then it finds the differences between the lower and upper possible number and returns the number with least difference. This is as good as rounding.

The quickest way would be to divide by 5, round and then multiply by 5. It's purely mathematical fact that this will work.
5*round(n/5)
And there's no need for the if statement deciding on when to use floor or ceil since round already defaults to this logic.
EDIT: As pointed out this works for all values except those ending in 2.5 when requiring that this rounds up (in practice many examples won't need this).
As Ashwin's answer accomplishes this already, I'll give a fix to do it on one line without a function definition, though it's not pretty:
5 * (int(x/5) + 1 - round(x/5 % 1))
Or slightly cleaner with ceil:
5*(math.ceil(x/5) - round(x/5 % 1))
exploiting the the fact that round behaves as we would like from above.
Even better, define:
def my_round(x): return int(x + 1) - round(x % 1)
def round5(x): return 5*my_round(x/5)
to 'fix' the round function and create a nice round5 function in 2 lines. This is what I'd do.

You could divide the number you are trying to round by 5, then take its round() and multiply again by five:
num = 707.466
int = num / 5 # returns 141.4932
rounded = round(int) # returns 141
answer = rounded * 5 # 705
Or as a function:
def round_to_five(num):
num = num / 5
num = round(num)
return num * 5

Hope this helps
# my standard point to which rounding shoulding happen
>>> standard_nums = [700, 702, 705, 708]
# example value I am taking
>>> my_num = 702.5
# this is how I would round my number
>>> ret = abs(standard_nums[0] - my_num)
>>> val = standard_nums[0]
>>> for each in standard_nums[1:]:
... if abs(each - my_num) < ret:
... ret = abs(each - my_num)
... val = each
...
>>> ret # min diff I can find
0.5
>>> val # value you are lookin for
702
>>>
## this above has a complexity of O(N)
## where N is the size of your standard number

Assuming that you use Python 3, would the following line do the job ?
5*(x//5)+5*(x%5>=2.5)
It seems to work for x being a scalar, numpy.array or a pandas.series

Related

Python removing first 3 digits in a number

Hopefully a simple one, I have a number, say 1234567.890 this number could be anything but will be this length.
How do I truncate the first 3 numbers so it turns into 4567.890?
This could be any number so subtracting 123000 will not work.
I'm working with map data in UTM coordinates (but that should not matter)
Example
x = 580992.528
y = 4275267.719
For x, I want 992.528
For y, I want 267.719
Note: y has an extra digit to the left of the decimal so 4 need removing
You can use slices for this:
x = 1234567.890
# This is still a float
x = float(str(x)[3:])
print(x)
Outputs:
4567.89
As [3:] gets the starts the index at 3 and continues to the end of the string
Update after your edit
The simplest way is to use Decimal:
from decimal import Decimal
def fmod(v, m=1000, /):
return float(Decimal(str(v)) % m)
print(fmod(x))
print(fmod(y))
Output
992.528
267.719
If you don't use string, you will have some problems with floating point in Python.
Demo:
n = 1234567.890
i = 0
while True:
m = int(n // 10**i)
if m < 1000:
break
i += 1
r = n % 10**i
Output:
>>> r
4567.889999999898
>>> round(r, 3)
4567.89
Same with Decimal from decimal module:
from decimal import Decimal
n = 1234567.890
n = Decimal(str(n))
i = 0
while True:
m = int(n // 10**i)
if m < 1000:
break
i += 1
r = n % 10**i
Output:
>>> r
Decimal('4567.89')
>>> float(r)
4567.89
This approach simply implements your idea.
int_len is the length of the integer part that we keep
sub is the rounded value that we will subtract the original float by
Code
Here is the code that implements your idea.
import math
def trim(n, digits):
int_len = len(str(int(n))) - digits # length of 4567
sub = math.floor(n / 10 **int_len) * 10**int_len
print(n - sub)
But as Kelly Bundy has pointed out, you can use modulo operation to avoid the complicated process of finding the subtrahend.
def trim(n, digits):
int_len = len(str(int(n))) - digits # length of 4567
print(n % 10**int_len)
Output
The floating point thing is a bit cursed and you may want to take Corralien's answer as an alternative.
>>> n = 1234567.890
>>> trim(n, 3)
4567.889999999898
def get_slice(number, split_n):
return number - (number // 10**split_n) * 10**split_n

SQRT using any method (f.e. Newton) but with fixed number of digits after separator

I need to calculate in Python 3 square root of number num (0 < num <= 1000000000000000 ) using any method, any mathematic algorithm. The problem is I need to calculate it to P (0 <= P <= 10000) digits after dot (floating number separator) and the result should be rounded down (always to smaller number). Of course, I cannot use math.sqrt().
So if num is 55 and P = 6, function should return:
7,416198
So if num is 55 and P = 10, function should return:
7,4161984870
Here is my code:
def square_root(num, P):
x = num
y = 1
e = 10 ** (-P)
while (x - y > e):
x = (x + y) / 2
y = num / x
return x
Should I use Decimal type?
For the most part, the algorithm you already have is correct. The main issue is precision, which, as you guessed, you can do with the Decimal class.
import Decimal
def square_root(num, P):
# need to set the decimal precision to more than enough digits to handle the full calculation
# (the number of decimal places, plus the number of digits in the original number,
# should be enough - this counts the numbers both before and after the decimal point)
# I add +2 to give some room to spare, as well
decimal.getcontext().prec = P + len(str(num)) + 2
# now, do the algorithm you have, except with everything as fixed-point Decimal objects
x = decimal.Decimal(num)
y = decimal.Decimal(1)
e = decimal.Decimal(10) ** decimal.Decimal(-P)
# important: I changed this to >= so that it runs when P=0.
# Otherwise we output 2 when P=0, when we should output 1.
while (x - y >= e):
x = (x + y) / 2
y = num / x
# now, truncate to exactly the desired number of digits
# this is straightforward - we can just use the built-in `round()` method with P
# we subtract e/2 to simulate always rounding down, since round() simply rounds to closest.
return round(x - (e / 2), P)
This works for an arbitrarily high precision:
>>> square_root(2, 0)
Decimal('1')
>>> square_root(2, 1)
Decimal('1.4')
>>> square_root(2, 3)
Decimal('1.414')
>>> square_root(2, 5)
Decimal('1.41421')
>>> square_root(2, 100)
Decimal('1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727')
>>> square_root(2, 10000)
Decimal('1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079896872533965463318088296406206152583523950547457502877599617298355752203375318570113543746034084988471603868999706990048150305440277903164542478230684929369186215805784631115966687130130156185689872372352885092648612494977154218334204285686060146824720771435854874155657069677653720226485447015858801620758474922657226002085584466521458398893944370926591800311388246468157082630100594858704003186480342194897278290641045072636881313739855256117322040245091227700226941127573627280495738108967504018369868368450725799364729060762996941380475654823728997180326802474420629269124859052181004459842150591120249441341728531478105803603371077309182869314710171111683916581726889419758716582152128229518488472089694633862891562882765952635140542267653239694617511291602408715510135150455381287560052631468017127402653969470240300517495318862925631385188163478001569369176881852378684052287837629389214300655869568685964595155501644724509836896036887323114389415576651040883914292338113206052433629485317049915771756228549741438999188021762430965206564211827316726257539594717255934637238632261482742622208671155839599926521176252698917540988159348640083457085181472231814204070426509056532333398436457865796796519267292399875366617215982578860263363617827495994219403777753681426217738799194551397231274066898329989895386728822856378697749662519966583525776198939322845344735694794962952168891485492538904755828834526096524096542889394538646625744927556381964410316979833061852019379384940057156333720548068540575867999670121372239475821426306585132217408832382947287617393647467837431960001592188807347857617252211867490424977366929207311096369721608933708661156734585334833295254675851644710757848602463600834449114818587655554286455123314219926311332517970608436559704352856410087918500760361009159465670676883605571740076756905096136719401324935605240185999105062108163597726431380605467010293569971042425105781749531057255934984451126922780344913506637568747760283162829605532422426957534529028838768446429173282770888318087025339852338122749990812371892540726475367850304821591801886167108972869229201197599880703818543332536460211082299279293072871780799888099176741774108983060800326311816427988231171543638696617029999341616148786860180455055539869131151860103863753250045581860448040750241195184305674533683613674597374423988553285179308960373898915173195874134428817842125021916951875593444387396189314549999906107587049090260883517636224749757858858368037457931157339802099986622186949922595913276423619410592100328026149874566599688874067956167391859572888642473463585886864496822386006983352642799056283165613913942557649062065186021647263033362975075697870606606856498160092718709292153132368281356988937097416504474590960537472796524477094099241238710614470543986743647338477454819100872886222149589529591187892149179833981083788278153065562315810360648675873036014502273208829351341387227684176678436905294286984908384557445794095986260742499549168028530773989382960362133539875320509199893607513906444495768456993471276364507163279154701597733548638939423257277540038260274785674172580951416307159597849818009443560379390985590168272154034581581521004936662953448827107292396602321638238266612626830502572781169451035379371568823365932297823192986064679789864092085609558142614363631004615594332550474493975933999125419532300932175304476533964706627611661753518754646209676345587386164880198848497479264045065444896910040794211816925796857563784881498986416854994916357614484047021033989215342377037233353115645944389703653166721949049351882905806307401346862641672470110653463493916407146285567980177933814424045269137066609777638784866238003392324370474115331872531906019165996455381157888413808433232105337674618121780142960928324113627525408873729051294073394794330619439569367020794295158782283493219316664111301549594698378977674344435393377099571349884078908508158923660700886581054709497904657229888808924612828160131337010290802909997456478495815456146487155163905024198579061310934587833062002622073724716766854554999049940857108099257599288932366154382719550057816251330381531465779079268685008069844284791524242754410268057563215653220618857512251130639370253629271619682512591920252160587011895967322442392674237344907646467273753479645988191498079317180024238554538860383683108007791824664627541174442500187277795181643834514634612990207633430179685543856316677235183893366670422221109391449302879638128398893117313084300421255501854985065294556377660314612559091046113847682823595924772286290426427361632645854433928772638603431498048963973633297548859256811492968361267258985738332164366634870234773026101061305072986115341299488087744731112295426527516536659117301423606265258690771982170370981046443604772267392829874152593069562063847108274082184906737233058743029709242899481739244078693752844010443990485208788519141935415129006817351703069386970590047425157655248078447362144105016200845444122255956202984725940352801906798068098300396453985685930458625260637797453559927747299064888745451242496076378010863900191058092874764720751109238605950195432281602088796215162338521612875228518025292876183257037172857406763944909825464422184654308806610580201584728406712630254593798906508168571371656685941300533197036596403376674146104956376510308366134893109478026812935573318905519705201845150399690986631525124116111925940552808564989319589834562331983683494880806171562439112866312797848371978953369015277600549805516635019785557110140555297633841275044686046476631832661165182067501204766991098721910444744032689436415959427921994423553718704299559240314091712848158543866005385713583639816309452407557009325168243441682408361979273372825215462246961533217026829950979089034594858878349439616204358422497397187113958927305092197054917176961600445580899427878880369169432894595147226722926124850696173163809410821860045286102696547576304310256027152313969482135519821409716549097319992834925674097490392297126348693414574933198041718076111963902278664075922434167762466236238913110270343304576368141128321326308582239456219598086612939996201234156176318174312420089014983848560480879864608393596492366514296812577314322914568716827621996118278269531574983802624651759054103976181287604216386134502213262727756612441133610775195557749508656360673786650623185640699122801875741785494661253275997697960597760590756489106661015838417202818530432119044657752554277543798726054881736198267581686283295260789932226683602838513512281059318591028641508157056319717315183136250243590414632122392176633982689368253150530059891547029095371932662073411234947433678846902013904978428521634144292145895582878476693946464267812219049785636355263368278051860098699248937786002398769169807656621943898544370805946433362333810587458162354756001365924352426571430834655457680023708146757325254702550747637471635067851599173693793251032682760628645914618204721486370370771926926823623334720379245964691810526139153086280291440965482563873092730426544662929045896063751918711469345361973324789572707031530930901921199199993615765003503984054067425387927527922724733566770607837911384488936261367657060263600315132952095395202854897384486256134924414708607086602676349978793420875836121947116994223848482595914304528107062601508969135303017720062717054402090669514915274597719705947695474095210287872557856880022193717743558110793930883384558648277291008629554566141306721230848740227121058686323388237413884428938155444647105755651468435702946635062893873569868688376480326519528414653517395302736120137420300986739838514321900436028982698293529399414129230580384565022707216815161941011449826301364900877048398488386090653368599054583895203185648041493272142390865164999431659207965953569430723112911629286797517156688905439322035691293324570208067194440497304943981408227829602799424541083166675921424835182723817205041039274288801556223380796147512433514731021284545944899444996000752437519570116683417447490795882099517836768023236517674972301487457742725994760962198432714835298611190272873584905217975908374197486026706053746231530039375212367867752848692195857137554269684827836317861109933680143915905974842858054516130230143979057016108898627779610750673332676048654929251399781390535882276893732204941483940135560356560442140176120605131806891989962606184831853401836237821726637580455247196266174925422852804571442048578342113228008528704205488992341278554812367615377071042544698685219911228354266349997127483660762462418207364666171283947484732804744304033441072004287271275670279567582429262719454580530026664899650795697781786219421720052371653694677041951119127046248360511302890464377511486948878496151188414719100012558838366606772084112351535588112677895715585904125762616010675131535802124273318710006358249545040995794072547989003168265123731190556682915194305370848930786919742829049038603723116099283424317122250994547150192866648787107951995180054633883844315481724635480244518030845273431000621371034625733060012349737443558180965678464641533905146569193245623531405779193698988423647183525375805257713311200797104068315492665402026046806818391437827214769063242469517128636738443139833371176159418699934662623453734523567940124168092291163609563721674528391709909146648507392051516056047378710615470216996074656930979442612146925615934256494019122989514732544715181263258368897282262833295240359700727863364604594707124174729468775705958157349962848099567839255474240448991887071069675242507745201229360810574142653234724064162141033353340551104521261750359028403745459186450472762434207177092979354010214096464502836834180407586081001407216192477179809859681115404464437285689592868319777977869346415984697451339177415379048778808300220583350467465553230285873258352')
Of course, you can also take str() of the return value to convert it into a string.

Print a large integer in Python

I'd like to print an large integer without the "e+XX" at the end in Python.
For example, when I write:
n = 100
k = 18
result = 1
i = 0
while i < k:
result = result * (n - i) / (i + 1)
i += 1
The result is 3.066451080298821e+19, and I would like to have 30664510802988208300.
If you want an integer, you have to use integer division, // instead of /, as mentioned in #farsil's deleted answer.
result = 1
k = 18
n = 100
for i in range(k):
result = result * (n - i) // (i + 1)
print(result)
This only gives the correct result if i + 1 is always a divisor of result * (n - i). However, this is always true, so we are fine.
You cannot use / because that will perform floating-point division, which will truncate the results to 56 bits. The correct result does not fit in 56 bits:
In [1]: int(float(30664510802988208300))
Out[1]: 30664510802988208128
# ^^^ oops... off by 172
Why is floor division safe?
In this case, when the division by 2 is performed, we have multiplied result by n and n-1, at least one of which is a multiple of 2. When i+1 is 3, then we have multiplied by n, n-1, and n-2, at least one of which is a multiple of 3. This pattern works for all numbers.
I think the question you really want to ask is 'how can I print a number in Python without scientific notation?'
The answer is, your number right now is a float. Try print(type(result)) and you will see it says float. You could type cast it to an integer by doing int(result), and it will show close to the full number, 30664510802988208128. It will be a bit off because of the memory size storage limitations of int vs float.
The better way to do this would be like:
result = 1
i = 0
while i < 18:
result = result * (100 - i) // (i + 1)
i += 1
print(result)
which will keep result as an int type. It now should print 30664510802988208300

How to convert floating point number to base 3 in python

How does one convert a base-10 floating point number in Python to a base-N floating point number?
Specifically in my case, I would like to convert numbers to base 3 (obtain the representation of floating point numbers in base 3), for calculations with the Cantor set.
After a bit of fiddling, here's what I came up with. I present it to you humbly, keeping in mind Ignacio's warning. Please let me know if you find any flaws. Among other things, I have no reason to believe that the precision argument provides anything more than a vague assurance that the first precision digits are pretty close to correct.
def base3int(x):
x = int(x)
exponents = range(int(math.log(x, 3)), -1, -1)
for e in exponents:
d = int(x // (3 ** e))
x -= d * (3 ** e)
yield d
def base3fraction(x, precision=1000):
x = x - int(x)
exponents = range(-1, (-precision - 1) * 2, -1)
for e in exponents:
d = int(x // (3 ** e))
x -= d * (3 ** e)
yield d
if x == 0: break
These are iterators returning ints. Let me know if you need string conversion; but I imagine you can handle that.
EDIT: Actually looking at this some more, it seems like a if x == 0: break line after the yield in base3fraction gives you pretty much arbitrary precision. I went ahead and added that. Still, I'm leaving in the precision argument; it makes sense to be able to limit that quantity.
Also, if you want to convert back to decimal fractions, this is what I used to test the above.
sum(d * (3 ** (-i - 1)) for i, d in enumerate(base3fraction(x)))
Update
For some reason I've felt inspired by this problem. Here's a much more generalized solution. This returns two generators that generate sequences of integers representing the integral and fractional part of a given number in an arbitrary base. Note that this only returns two generators to distinguish between the parts of the number; the algorithm for generating digits is the same in both cases.
def convert_base(x, base=3, precision=None):
length_of_int = int(math.log(x, base))
iexps = range(length_of_int, -1, -1)
if precision == None: fexps = itertools.count(-1, -1)
else: fexps = range(-1, -int(precision + 1), -1)
def cbgen(x, base, exponents):
for e in exponents:
d = int(x // (base ** e))
x -= d * (base ** e)
yield d
if x == 0 and e < 0: break
return cbgen(int(x), base, iexps), cbgen(x - int(x), base, fexps)
Although 8 years have passed, I think it is worthwhile to mention a more compact solution.
def baseConversion( x=1, base=3, decimals=2 ):
import math
n_digits = math.floor(-math.log(x, base))#-no. of digits in front of decimal point
x_newBase = 0#initialize
for i in range( n_digits, decimals+1 ):
x_newBase = x_newBase + int(x*base**i) % base * 10**(-i)
return x_newBase
For example calling the function to convert the number 5+1/9+1/27
def baseConversion( x=5+1/9+1/27, base=3, decimals=2 )
12.01
def baseConversion( x=5+1/9+1/27, base=3, decimals=3 )
12.011
You may try this solution to convert a float string to a given base.
def eval_strint(s, base=2):
assert type(s) is str
assert 2 <= base <= 36
###
### YOUR CODE HERE
###
return int(s,base)
def is_valid_strfrac(s, base=2):
return all([is_valid_strdigit(c, base) for c in s if c != '.']) \
and (len([c for c in s if c == '.']) <= 1)
def eval_strfrac(s, base=2):
assert is_valid_strfrac(s, base), "'{}' contains invalid digits for a base-{} number.".format(s, base)
stg = s.split(".")
float_point=0.0
if len(stg) > 1:
float_point = (eval_strint(stg[1],base) * (base**(-len(stg[1]))))
stg_float = eval_strint(stg[0],base) + float_point
return stg_float

Generating digits of square root of 2

I want to generate the digits of the square root of two to 3 million digits.
I am aware of Newton-Raphson but I don't have much clue how to implement it in C or C++ due to lack of biginteger support. Can somebody point me in the right direction?
Also, if anybody knows how to do it in python (I'm a beginner), I would also appreciate it.
You could try using the mapping:
a/b -> (a+2b)/(a+b) starting with a= 1, b= 1. This converges to sqrt(2) (in fact gives the continued fraction representations of it).
Now the key point: This can be represented as a matrix multiplication (similar to fibonacci)
If a_n and b_n are the nth numbers in the steps then
[1 2] [a_n b_n]T = [a_(n+1) b_(n+1)]T
[1 1]
which now gives us
[1 2]n [a_1 b_1]T = [a_(n+1) b_(n+1)]T
[1 1]
Thus if the 2x2 matrix is A, we need to compute An which can be done by repeated squaring and only uses integer arithmetic (so you don't have to worry about precision issues).
Also note that the a/b you get will always be in reduced form (as gcd(a,b) = gcd(a+2b, a+b)), so if you are thinking of using a fraction class to represent the intermediate results, don't!
Since the nth denominators is like (1+sqrt(2))^n, to get 3 million digits you would likely need to compute till the 3671656th term.
Note, even though you are looking for the ~3.6 millionth term, repeated squaring will allow you to compute the nth term in O(Log n) multiplications and additions.
Also, this can easily be made parallel, unlike the iterative ones like Newton-Raphson etc.
EDIT: I like this version better than the previous. It's a general solution that accepts both integers and decimal fractions; with n = 2 and precision = 100000, it takes about two minutes. Thanks to Paul McGuire for his suggestions & other suggestions welcome!
def sqrt_list(n, precision):
ndigits = [] # break n into list of digits
n_int = int(n)
n_fraction = n - n_int
while n_int: # generate list of digits of integral part
ndigits.append(n_int % 10)
n_int /= 10
if len(ndigits) % 2: ndigits.append(0) # ndigits will be processed in groups of 2
decimal_point_index = len(ndigits) / 2 # remember decimal point position
while n_fraction: # insert digits from fractional part
n_fraction *= 10
ndigits.insert(0, int(n_fraction))
n_fraction -= int(n_fraction)
if len(ndigits) % 2: ndigits.insert(0, 0) # ndigits will be processed in groups of 2
rootlist = []
root = carry = 0 # the algorithm
while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
carry = carry * 100
if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
x = 9
while (20 * root + x) * x > carry:
x -= 1
carry -= (20 * root + x) * x
root = root * 10 + x
rootlist.append(x)
return rootlist, decimal_point_index
As for arbitrary big numbers you could have a look at The GNU Multiple Precision Arithmetic Library (for C/C++).
For work? Use a library!
For fun? Good for you :)
Write a program to imitate what you would do with pencil and paper. Start with 1 digit, then 2 digits, then 3, ..., ...
Don't worry about Newton or anybody else. Just do it your way.
Here is a short version for calculating the square root of an integer a to digits of precision. It works by finding the integer square root of a after multiplying by 10 raised to the 2 x digits.
def sqroot(a, digits):
a = a * (10**(2*digits))
x_prev = 0
x_next = 1 * (10**digits)
while x_prev != x_next:
x_prev = x_next
x_next = (x_prev + (a // x_prev)) >> 1
return x_next
Just a few caveats.
You'll need to convert the result to a string and add the decimal point at the correct location (if you want the decimal point printed).
Converting a very large integer to a string isn't very fast.
Dividing very large integers isn't very fast (in Python) either.
Depending on the performance of your system, it may take an hour or longer to calculate the square root of 2 to 3 million decimal places.
I haven't proven the loop will always terminate. It may oscillate between two values differing in the last digit. Or it may not.
The nicest way is probably using the continued fraction expansion [1; 2, 2, ...] the square root of two.
def root_two_cf_expansion():
yield 1
while True:
yield 2
def z(a,b,c,d, contfrac):
for x in contfrac:
while a > 0 and b > 0 and c > 0 and d > 0:
t = a // c
t2 = b // d
if not t == t2:
break
yield t
a = (10 * (a - c*t))
b = (10 * (b - d*t))
# continue with same fraction, don't pull new x
a, b = x*a+b, a
c, d = x*c+d, c
for digit in rdigits(a, c):
yield digit
def rdigits(p, q):
while p > 0:
if p > q:
d = p // q
p = p - q * d
else:
d = (10 * p) // q
p = 10 * p - q * d
yield d
def decimal(contfrac):
return z(1,0,0,1,contfrac)
decimal((root_two_cf_expansion()) returns an iterator of all the decimal digits. t1 and t2 in the algorithm are minimum and maximum values of the next digit. When they are equal, we output that digit.
Note that this does not handle certain exceptional cases such as negative numbers in the continued fraction.
(This code is an adaptation of Haskell code for handling continued fractions that has been floating around.)
Well, the following is the code that I wrote. It generated a million digits after the decimal for the square root of 2 in about 60800 seconds for me, but my laptop was sleeping when it was running the program, it should be faster that. You can try to generate 3 million digits, but it might take a couple days to get it.
def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
if number[a]=='.':
decimal_point_locaiton=a
break
if a==len(number)-1:
number+='.'
decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
number='0'+number
decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
if number[a]!='0':
list.append(eval(number[a:a+2]))
else:
try:
list.append(eval(number[a+1]))
except IndexError:
pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
try:
c=c*100+list[a+1]
except IndexError:
c=c*100
while c!=0:
x=0
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
c=c*100
if len(ans)-decimal_point_ans>=digits_after_decimal:
break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
Python already supports big integers out of the box, and if that's the only thing holding you back in C/C++ you can always write a quick container class yourself.
The only problem you've mentioned is a lack of big integers. If you don't want to use a library for that, then are you looking for help writing such a class?
Here's a more efficient integer square root function (in Python 3.x) that should terminate in all cases. It starts with a number much closer to the square root, so it takes fewer steps. Note that int.bit_length requires Python 3.1+. Error checking left out for brevity.
def isqrt(n):
x = (n >> n.bit_length() // 2) + 1
result = (x + n // x) // 2
while abs(result - x) > 1:
x = result
result = (x + n // x) // 2
while result * result > n:
result -= 1
return result

Categories