Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
84534ce4b8
30 changed files with 894 additions and 494 deletions
|
|
@ -201,7 +201,10 @@ proc find*(s: string, pattern: TRegEx, start = 0): int =
|
|||
return rawMatches[0]
|
||||
|
||||
iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
|
||||
## yields all matching *substrings* of `s` that match `pattern`.
|
||||
## Yields all matching *substrings* of `s` that match `pattern`.
|
||||
##
|
||||
## Note that since this is an iterator you should not modify the string you
|
||||
## are iterating over: bad things could happen.
|
||||
var i = int32(start)
|
||||
var rawMatches: array[0..maxSubpatterns * 3 - 1, cint]
|
||||
while true:
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
|
|||
if cmpIgnoreCase(x.elemName, result.tag) == 0:
|
||||
next(x)
|
||||
else:
|
||||
echo "5; expected: ", result.htmltag, " ", x.elemName
|
||||
#echo "5; expected: ", result.htmltag, " ", x.elemName
|
||||
errors.add(expected(x, result))
|
||||
# do not skip it here!
|
||||
break
|
||||
|
|
|
|||
83
lib/pure/numeric.nim
Normal file
83
lib/pure/numeric.nim
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2013 Robert Persson
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
|
||||
type TOneVarFunction* =proc (x:float):float
|
||||
|
||||
proc brent*(xmin,xmax:float ,function:TOneVarFunction, tol:float,maxiter=1000):
|
||||
tuple[rootx, rooty: float, success: bool]=
|
||||
## Searches `function` for a root between `xmin` and `xmax`
|
||||
## using brents method. If the function value at `xmin`and `xmax` has the
|
||||
## same sign, `rootx`/`rooty` is set too the extrema value closest to x-axis
|
||||
## and succes is set to false.
|
||||
## Otherwise there exists at least one root and success is set to true.
|
||||
## This root is searched for at most `maxiter` iterations.
|
||||
## If `tol` tolerance is reached within `maxiter` iterations
|
||||
## the root refinement stops and success=true.
|
||||
|
||||
# see http://en.wikipedia.org/wiki/Brent%27s_method
|
||||
var
|
||||
a=xmin
|
||||
b=xmax
|
||||
c=a
|
||||
d=1.0e308
|
||||
fa=function(a)
|
||||
fb=function(b)
|
||||
fc=fa
|
||||
s=0.0
|
||||
fs=0.0
|
||||
mflag:bool
|
||||
i=0
|
||||
tmp2:float
|
||||
|
||||
if fa*fb>=0:
|
||||
if abs(fa)<abs(fb):
|
||||
return (a,fa,false)
|
||||
else:
|
||||
return (b,fb,false)
|
||||
|
||||
if abs(fa)<abs(fb):
|
||||
swap(fa,fb)
|
||||
swap(a,b)
|
||||
|
||||
while fb!=0.0 and abs(a-b)>tol:
|
||||
if fa!=fc and fb!=fc: # inverse quadratic interpolation
|
||||
s = a * fb * fc / (fa - fb) / (fa - fc) + b * fa * fc / (fb - fa) / (fb - fc) + c * fa * fb / (fc - fa) / (fc - fb)
|
||||
else: #secant rule
|
||||
s = b - fb * (b - a) / (fb - fa)
|
||||
tmp2 = (3.0 * a + b) / 4.0
|
||||
if not((s > tmp2 and s < b) or (s < tmp2 and s > b)) or
|
||||
(mflag and abs(s - b) >= (abs(b - c) / 2.0)) or
|
||||
(not mflag and abs(s - b) >= abs(c - d) / 2.0):
|
||||
s=(a+b)/2.0
|
||||
mflag=true
|
||||
else:
|
||||
if (mflag and (abs(b - c) < tol)) or (not mflag and (abs(c - d) < tol)):
|
||||
s=(a+b)/2.0
|
||||
mflag=true
|
||||
else:
|
||||
mflag=false
|
||||
fs = function(s)
|
||||
d = c
|
||||
c = b
|
||||
fc = fb
|
||||
if fa * fs<0.0:
|
||||
b=s
|
||||
fb=fs
|
||||
else:
|
||||
a=s
|
||||
fa=fs
|
||||
if abs(fa)<abs(fb):
|
||||
swap(a,b)
|
||||
swap(fa,fb)
|
||||
inc i
|
||||
if i>maxiter:
|
||||
break
|
||||
|
||||
return (b,fb,true)
|
||||
|
|
@ -474,8 +474,17 @@ proc JoinPath*(head, tail: string): string {.
|
|||
## .. code-block:: nimrod
|
||||
## "usr/lib"
|
||||
##
|
||||
## If head is the empty string, tail is returned.
|
||||
## If tail is the empty string, head is returned.
|
||||
## If head is the empty string, tail is returned. If tail is the empty
|
||||
## string, head is returned with a trailing path separator. If tail starts
|
||||
## with a path separator it will be removed when concatenated to head. Other
|
||||
## path separators not located on boundaries won't be modified. More
|
||||
## examples on Unix:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## assert JoinPath("usr", "") == "usr/"
|
||||
## assert JoinPath("", "lib") == "lib"
|
||||
## assert JoinPath("", "/lib") == "/lib"
|
||||
## assert JoinPath("usr/", "/lib") == "usr/lib"
|
||||
if len(head) == 0:
|
||||
result = tail
|
||||
elif head[len(head)-1] in {DirSep, AltSep}:
|
||||
|
|
@ -491,15 +500,24 @@ proc JoinPath*(head, tail: string): string {.
|
|||
|
||||
proc JoinPath*(parts: varargs[string]): string {.noSideEffect,
|
||||
rtl, extern: "nos$1OpenArray".} =
|
||||
## The same as `JoinPath(head, tail)`, but works with any number
|
||||
## of directory parts.
|
||||
## The same as `JoinPath(head, tail)`, but works with any number of directory
|
||||
## parts. You need to pass at least one element or the proc will assert in
|
||||
## debug builds and crash on release builds.
|
||||
result = parts[0]
|
||||
for i in 1..high(parts):
|
||||
result = JoinPath(result, parts[i])
|
||||
|
||||
proc `/` * (head, tail: string): string {.noSideEffect.} =
|
||||
## The same as ``joinPath(head, tail)``
|
||||
return joinPath(head, tail)
|
||||
## The same as ``JoinPath(head, tail)``
|
||||
##
|
||||
## Here are some examples for Unix:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## assert "usr" / "" == "usr/"
|
||||
## assert "" / "lib" == "lib"
|
||||
## assert "" / "/lib" == "/lib"
|
||||
## assert "usr/" / "/lib" == "usr/lib"
|
||||
return JoinPath(head, tail)
|
||||
|
||||
proc SplitPath*(path: string): tuple[head, tail: string] {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
|
|
@ -814,8 +832,13 @@ proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
|||
|
||||
proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO, FWriteIO].} =
|
||||
## Copies a file from `source` to `dest`. If this fails,
|
||||
## `EOS` is raised.
|
||||
## Copies a file from `source` to `dest`.
|
||||
##
|
||||
## If this fails, `EOS` is raised. On the Windows platform this proc will
|
||||
## copy the source file's attributes into dest. On other platforms you need
|
||||
## to use getFilePermissions and setFilePermissions to copy them by hand,
|
||||
## otherwise `dest` will inherit the default permissions of a newly created
|
||||
## file for the user.
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
let s = newWideCString(source)
|
||||
|
|
@ -1498,7 +1521,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
|||
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
||||
# iterate over any path in the $PATH environment variable
|
||||
for p in split(string(getEnv("PATH")), {PathSep}):
|
||||
var x = joinPath(p, result)
|
||||
var x = JoinPath(p, result)
|
||||
if ExistsFile(x): return x
|
||||
|
||||
proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} =
|
||||
|
|
|
|||
|
|
@ -27,8 +27,24 @@ proc toLower(c: char): char {.inline.} =
|
|||
|
||||
proc parseHex*(s: string, number: var int, start = 0): int {.
|
||||
rtl, extern: "npuParseHex", noSideEffect.} =
|
||||
## parses a hexadecimal number and stores its value in ``number``. Returns
|
||||
## the number of the parsed characters or 0 in case of an error.
|
||||
## Parses a hexadecimal number and stores its value in ``number``.
|
||||
##
|
||||
## Returns the number of the parsed characters or 0 in case of an error. This
|
||||
## proc is sensitive to the already existing value of ``number`` and will
|
||||
## likely not do what you want unless you make sure ``number`` is zero. You
|
||||
## can use this feature to *chain* calls, though the result int will quickly
|
||||
## overflow. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## var value = 0
|
||||
## discard parseHex("0x38", value)
|
||||
## assert value == 56
|
||||
## discard parseHex("0x34", value)
|
||||
## assert value == 56 * 256 + 52
|
||||
## value = -1
|
||||
## discard parseHex("0x38", value)
|
||||
## assert value == -200
|
||||
##
|
||||
var i = start
|
||||
var foundDigit = false
|
||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||
|
|
@ -383,6 +399,14 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind,
|
|||
when isMainModule:
|
||||
for k, v in interpolatedFragments("$test{} $this is ${an{ example}} "):
|
||||
echo "(", k, ", \"", v, "\")"
|
||||
var value = 0
|
||||
discard parseHex("0x38", value)
|
||||
assert value == 56
|
||||
discard parseHex("0x34", value)
|
||||
assert value == 56 * 256 + 52
|
||||
value = -1
|
||||
discard parseHex("0x38", value)
|
||||
assert value == -200
|
||||
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
367
lib/pure/poly.nim
Normal file
367
lib/pure/poly.nim
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2013 Robert Persson
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import math
|
||||
import strutils
|
||||
import numeric
|
||||
|
||||
type
|
||||
TPoly* = object
|
||||
cofs:seq[float]
|
||||
|
||||
|
||||
proc degree*(p:TPoly):int=
|
||||
## Returns the degree of the polynomial,
|
||||
## that is the number of coefficients-1
|
||||
return p.cofs.len-1
|
||||
|
||||
|
||||
proc eval*(p:TPoly,x:float):float=
|
||||
## Evaluates a polynomial function value for `x`
|
||||
## quickly using Horners method
|
||||
var n=p.degree
|
||||
result=p.cofs[n]
|
||||
dec n
|
||||
while n>=0:
|
||||
result = result*x+p.cofs[n]
|
||||
dec n
|
||||
|
||||
proc `[]` *(p:TPoly;idx:int):float=
|
||||
## Gets a coefficient of the polynomial.
|
||||
## p[2] will returns the quadric term, p[3] the cubic etc.
|
||||
## Out of bounds index will return 0.0.
|
||||
if idx<0 or idx>p.degree:
|
||||
return 0.0
|
||||
return p.cofs[idx]
|
||||
|
||||
proc `[]=` *(p:var TPoly;idx:int,v:float)=
|
||||
## Sets an coefficient of the polynomial by index.
|
||||
## p[2] set the quadric term, p[3] the cubic etc.
|
||||
## If index is out of range for the coefficients,
|
||||
## the polynomial grows to the smallest needed degree.
|
||||
assert(idx>=0)
|
||||
|
||||
if idx>p.degree: #polynomial must grow
|
||||
var oldlen=p.cofs.len
|
||||
p.cofs.setLen(idx+1)
|
||||
for q in oldlen.. <high(p.cofs):
|
||||
p.cofs[q]=0.0 #new-grown coefficients set to zero
|
||||
|
||||
p.cofs[idx]=v
|
||||
|
||||
|
||||
iterator items*(p:TPoly):float=
|
||||
## Iterates through the corfficients of the polynomial.
|
||||
var i=p.degree
|
||||
while i>=0:
|
||||
yield p[i]
|
||||
dec i
|
||||
|
||||
proc clean*(p:var TPoly;zerotol=0.0)=
|
||||
## Removes leading zero coefficients of the polynomial.
|
||||
## An optional tolerance can be given for what's considered zero.
|
||||
var n=p.degree
|
||||
var relen=false
|
||||
|
||||
while n>0 and abs(p[n])<=zerotol: # >0 => keep at least one coefficient
|
||||
dec n
|
||||
relen=true
|
||||
|
||||
if relen: p.cofs.setLen(n+1)
|
||||
|
||||
|
||||
proc `$` *(p:TPoly):string =
|
||||
## Gets a somewhat reasonable string representation of the polynomial
|
||||
## The format should be compatible with most online function plotters,
|
||||
## for example directly in google search
|
||||
result=""
|
||||
var first=true #might skip + sign if first coefficient
|
||||
|
||||
for idx in countdown(p.degree,0):
|
||||
let a=p[idx]
|
||||
|
||||
if a==0.0:
|
||||
continue
|
||||
|
||||
if a>= 0.0 and not first:
|
||||
result.add('+')
|
||||
first=false
|
||||
|
||||
if a!=1.0 or idx==0:
|
||||
result.add(formatFloat(a,ffDefault,0))
|
||||
if idx>=2:
|
||||
result.add("x^" & $idx)
|
||||
elif idx==1:
|
||||
result.add("x")
|
||||
|
||||
if result=="":
|
||||
result="0"
|
||||
|
||||
|
||||
proc derivative*(p:TPoly):TPoly=
|
||||
## Returns a new polynomial, which is the derivative of `p`
|
||||
newSeq[float](result.cofs,p.degree)
|
||||
for idx in 0..high(result.cofs):
|
||||
result.cofs[idx]=p.cofs[idx+1]*float(idx+1)
|
||||
|
||||
proc diff*(p:TPoly,x:float):float=
|
||||
## Evaluates the differentiation of a polynomial with
|
||||
## respect to `x` quickly using a modifed Horners method
|
||||
var n=p.degree
|
||||
result=p[n]*float(n)
|
||||
dec n
|
||||
while n>=1:
|
||||
result = result*x+p[n]*float(n)
|
||||
dec n
|
||||
|
||||
proc integral*(p:TPoly):TPoly=
|
||||
## Returns a new polynomial which is the indefinite
|
||||
## integral of `p`. The constant term is set to 0.0
|
||||
newSeq(result.cofs,p.cofs.len+1)
|
||||
result.cofs[0]=0.0 #constant arbitrary term, use 0.0
|
||||
for i in 1..high(result.cofs):
|
||||
result.cofs[i]=p.cofs[i-1]/float(i)
|
||||
|
||||
|
||||
proc integrate*(p:TPoly;xmin,xmax:float):float=
|
||||
## Computes the definite integral of `p` between `xmin` and `xmax`
|
||||
## quickly using a modified version of Horners method
|
||||
var
|
||||
n=p.degree
|
||||
s1=p[n]/float(n+1)
|
||||
s2=s1
|
||||
fac:float
|
||||
|
||||
dec n
|
||||
while n>=0:
|
||||
fac=p[n]/float(n+1)
|
||||
s1 = s1*xmin+fac
|
||||
s2 = s2*xmax+fac
|
||||
dec n
|
||||
|
||||
result=s2*xmax-s1*xmin
|
||||
|
||||
proc initPoly*(cofs:varargs[float]):TPoly=
|
||||
## Initializes a polynomial with given coefficients.
|
||||
## The most significant coefficient is first, so to create x^2-2x+3:
|
||||
## intiPoly(1.0,-2.0,3.0)
|
||||
if len(cofs)<=0:
|
||||
result.cofs= @[0.0] #need at least one coefficient
|
||||
else:
|
||||
# reverse order of coefficients so indexing matches degree of
|
||||
# coefficient...
|
||||
result.cofs= @[]
|
||||
for idx in countdown(cofs.len-1,0):
|
||||
result.cofs.add(cofs[idx])
|
||||
|
||||
result.clean #remove leading zero terms
|
||||
|
||||
|
||||
proc divMod*(p,d:TPoly;q,r:var TPoly)=
|
||||
## Divides `p` with `d`, and stores the quotinent in `q` and
|
||||
## the remainder in `d`
|
||||
var
|
||||
pdeg=p.degree
|
||||
ddeg=d.degree
|
||||
power=p.degree-d.degree
|
||||
ratio:float
|
||||
|
||||
r.cofs = p.cofs #initial remainder=numerator
|
||||
if power<0: #denominator is larger than numerator
|
||||
q.cofs= @ [0.0] #quotinent is 0.0
|
||||
return # keep remainder as numerator
|
||||
|
||||
q.cofs=newSeq[float](power+1)
|
||||
|
||||
for i in countdown(pdeg,ddeg):
|
||||
ratio=r.cofs[i]/d.cofs[ddeg]
|
||||
|
||||
q.cofs[i-ddeg]=ratio
|
||||
r.cofs[i]=0.0
|
||||
|
||||
for j in countup(0,<ddeg):
|
||||
var idx=i-ddeg+j
|
||||
r.cofs[idx] = r.cofs[idx] - d.cofs[j]*ratio
|
||||
|
||||
r.clean # drop zero coefficients in remainder
|
||||
|
||||
proc `+` *(p1:TPoly,p2:TPoly):TPoly=
|
||||
## Adds two polynomials
|
||||
var n=max(p1.cofs.len,p2.cofs.len)
|
||||
newSeq(result.cofs,n)
|
||||
|
||||
for idx in countup(0,n-1):
|
||||
result[idx]=p1[idx]+p2[idx]
|
||||
|
||||
result.clean # drop zero coefficients in remainder
|
||||
|
||||
proc `*` *(p1:TPoly,p2:TPoly):TPoly=
|
||||
## Multiplies the polynomial `p1` with `p2`
|
||||
var
|
||||
d1=p1.degree
|
||||
d2=p2.degree
|
||||
n=d1+d2
|
||||
idx:int
|
||||
|
||||
newSeq(result.cofs,n)
|
||||
|
||||
for i1 in countup(0,d1):
|
||||
for i2 in countup(0,d2):
|
||||
idx=i1+i2
|
||||
result[idx]=result[idx]+p1[i1]*p2[i2]
|
||||
|
||||
result.clean
|
||||
|
||||
proc `*` *(p:TPoly,f:float):TPoly=
|
||||
## Multiplies the polynomial `p` with a real number
|
||||
newSeq(result.cofs,p.cofs.len)
|
||||
for i in 0..high(p.cofs):
|
||||
result[i]=p.cofs[i]*f
|
||||
result.clean
|
||||
|
||||
proc `*` *(f:float,p:TPoly):TPoly=
|
||||
## Multiplies a real number with a polynomial
|
||||
return p*f
|
||||
|
||||
proc `-`*(p:TPoly):TPoly=
|
||||
## Negates a polynomial
|
||||
result=p
|
||||
for i in countup(0,<result.cofs.len):
|
||||
result.cofs[i]= -result.cofs[i]
|
||||
|
||||
proc `-` *(p1:TPoly,p2:TPoly):TPoly=
|
||||
## Subtract `p1` with `p2`
|
||||
var n=max(p1.cofs.len,p2.cofs.len)
|
||||
newSeq(result.cofs,n)
|
||||
|
||||
for idx in countup(0,n-1):
|
||||
result[idx]=p1[idx]-p2[idx]
|
||||
|
||||
result.clean # drop zero coefficients in remainder
|
||||
|
||||
proc `/`*(p:TPoly,f:float):TPoly=
|
||||
## Divides polynomial `p` with a real number `f`
|
||||
newSeq(result.cofs,p.cofs.len)
|
||||
for i in 0..high(p.cofs):
|
||||
result[i]=p.cofs[i]/f
|
||||
result.clean
|
||||
|
||||
proc `/` *(p,q:TPoly):TPoly=
|
||||
## Divides polynomial `p` with polynomial `q`
|
||||
var dummy:TPoly
|
||||
p.divMod(q,result,dummy)
|
||||
|
||||
proc `mod` *(p,q:TPoly):TPoly=
|
||||
## Computes the polynomial modulo operation,
|
||||
## that is the remainder of `p`/`q`
|
||||
var dummy:TPoly
|
||||
p.divMod(q,dummy,result)
|
||||
|
||||
|
||||
proc normalize*(p:var TPoly)=
|
||||
## Multiplies the polynomial inplace by a term so that
|
||||
## the leading term is 1.0.
|
||||
## This might lead to an unstable polynomial
|
||||
## if the leading term is zero.
|
||||
p=p/p[p.degree]
|
||||
|
||||
|
||||
proc solveQuadric*(a,b,c:float;zerotol=0.0):seq[float]=
|
||||
## Solves the quadric equation `ax^2+bx+c`, with a possible
|
||||
## tolerance `zerotol` to find roots of curves just 'touching'
|
||||
## the x axis. Returns sequence with 0,1 or 2 solutions.
|
||||
|
||||
var p,q,d:float
|
||||
|
||||
p=b/(2.0*a)
|
||||
|
||||
if p==inf or p==neginf: #linear equation..
|
||||
var linrt= -c/b
|
||||
if linrt==inf or linrt==neginf: #constant only
|
||||
return @[]
|
||||
return @[linrt]
|
||||
|
||||
q=c/a
|
||||
d=p*p-q
|
||||
|
||||
if d<0.0:
|
||||
#check for inside zerotol range for neg. roots
|
||||
var err=a*p*p-b*p+c #evaluate error at parabola center axis
|
||||
if(err<=zerotol): return @[-p]
|
||||
return @[]
|
||||
else:
|
||||
var sr=sqrt(d)
|
||||
result= @[-sr-p,sr-p]
|
||||
|
||||
proc getRangeForRoots(p:TPoly):tuple[xmin,xmax:float]=
|
||||
## helper function for `roots` function
|
||||
## quickly computes a range, guaranteed to contain
|
||||
## all the real roots of the polynomial
|
||||
# see http://www.mathsisfun.com/algebra/polynomials-bounds-zeros.html
|
||||
|
||||
var deg=p.degree
|
||||
var d=p[deg]
|
||||
var bound1,bound2:float
|
||||
|
||||
for i in countup(0,deg):
|
||||
var c=abs(p.cofs[i]/d)
|
||||
bound1=max(bound1,c+1.0)
|
||||
bound2=bound2+c
|
||||
|
||||
bound2=max(1.0,bound2)
|
||||
result.xmax=min(bound1,bound2)
|
||||
result.xmin= -result.xmax
|
||||
|
||||
|
||||
proc addRoot(p:TPoly,res:var seq[float],xp0,xp1,tol,zerotol,mergetol:float,maxiter:int)=
|
||||
## helper function for `roots` function
|
||||
## try to do a numeric search for a single root in range xp0-xp1,
|
||||
## adding it to `res` (allocating `res` if nil)
|
||||
var br=brent(xp0,xp1, proc(x:float):float=p.eval(x),tol)
|
||||
if br.success:
|
||||
if res.len==0 or br.rootx>=res[high(res)]+mergetol: #dont add equal roots.
|
||||
res.add(br.rootx)
|
||||
else:
|
||||
#this might be a 'touching' case, check function value against
|
||||
#zero tolerance
|
||||
if abs(br.rooty)<=zerotol:
|
||||
if res.len==0 or br.rootx>=res[high(res)]+mergetol: #dont add equal roots.
|
||||
res.add(br.rootx)
|
||||
|
||||
|
||||
proc roots*(p:TPoly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq[float]=
|
||||
## Computes the real roots of the polynomial `p`
|
||||
## `tol` is the tolerance used to break searching for each root when reached.
|
||||
## `zerotol` is the tolerance, which is 'close enough' to zero to be considered a root
|
||||
## and is used to find roots for curves that only 'touch' the x-axis.
|
||||
## `mergetol` is the tolerance, of which two x-values are considered beeing the same root.
|
||||
## `maxiter` can be used to limit the number of iterations for each root.
|
||||
## Returns a (possibly empty) sorted sequence with the solutions.
|
||||
var deg=p.degree
|
||||
if deg<=0: #constant only => no roots
|
||||
return @[]
|
||||
elif p.degree==1: #linear
|
||||
var linrt= -p.cofs[0]/p.cofs[1]
|
||||
if linrt==inf or linrt==neginf:
|
||||
return @[] #constant only => no roots
|
||||
return @[linrt]
|
||||
elif p.degree==2:
|
||||
return solveQuadric(p.cofs[2],p.cofs[1],p.cofs[0],zerotol)
|
||||
else:
|
||||
# degree >=3 , find min/max points of polynomial with recursive
|
||||
# derivative and do a numerical search for root between each min/max
|
||||
var range=p.getRangeForRoots()
|
||||
var minmax=p.derivative.roots(tol,zerotol,mergetol)
|
||||
result= @[]
|
||||
if minmax!=nil: #ie. we have minimas/maximas in this function
|
||||
for x in minmax.items:
|
||||
addRoot(p,result,range.xmin,x,tol,zerotol,mergetol,maxiter)
|
||||
range.xmin=x
|
||||
addRoot(p,result,range.xmin,range.xmax,tol,zerotol,mergetol,maxiter)
|
||||
|
||||
|
|
@ -440,16 +440,23 @@ proc repeatStr*(count: int, s: string): string {.noSideEffect,
|
|||
result = newStringOfCap(count*s.len)
|
||||
for i in 0..count-1: result.add(s)
|
||||
|
||||
proc align*(s: string, count: int): string {.
|
||||
proc align*(s: string, count: int, padding = ' '): string {.
|
||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||
## Aligns a string `s` with spaces, so that is of length `count`. Spaces are
|
||||
## added before `s` resulting in right alignment. If ``s.len >= count``, no
|
||||
## spaces are added and `s` is returned unchanged. If you need to left align
|
||||
## a string use the repeatChar proc.
|
||||
## Aligns a string `s` with `padding`, so that is of length `count`.
|
||||
## `padding` characters (by default spaces) are added before `s` resulting in
|
||||
## right alignment. If ``s.len >= count``, no spaces are added and `s` is
|
||||
## returned unchanged. If you need to left align a string use the
|
||||
## ``repeatChar`` proc. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## assert align("abc", 4) == " abc"
|
||||
## assert align("a", 0) == "a"
|
||||
## assert align("1232", 6) == " 1232"
|
||||
## assert align("1232", 6, '#') == "##1232"
|
||||
if s.len < count:
|
||||
result = newString(count)
|
||||
var spaces = count - s.len
|
||||
for i in 0..spaces-1: result[i] = ' '
|
||||
for i in 0..spaces-1: result[i] = padding
|
||||
for i in spaces..count-1: result[i] = s[i-spaces]
|
||||
else:
|
||||
result = s
|
||||
|
|
@ -1211,6 +1218,7 @@ when isMainModule:
|
|||
doAssert align("abc", 4) == " abc"
|
||||
doAssert align("a", 0) == "a"
|
||||
doAssert align("1232", 6) == " 1232"
|
||||
doAssert align("1232", 6, '#') == "##1232"
|
||||
echo wordWrap(""" this is a long text -- muchlongerthan10chars and here
|
||||
it goes""", 10, false)
|
||||
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
||||
|
|
|
|||
|
|
@ -2392,8 +2392,10 @@ proc `[]=`*[T](s: var seq[T], x: TSlice[int], b: openArray[T]) =
|
|||
spliceImpl(s, a, L, b)
|
||||
|
||||
proc slurp*(filename: string): string {.magic: "Slurp".}
|
||||
## This is an alias for ``staticRead``.
|
||||
|
||||
proc staticRead*(filename: string): string {.magic: "Slurp".}
|
||||
## compile-time ``readFile`` proc for easy `resource`:idx: embedding:
|
||||
## Compile-time ``readFile`` proc for easy `resource`:idx: embedding:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## const myResource = staticRead"mydatafile.bin"
|
||||
|
|
@ -2402,9 +2404,11 @@ proc staticRead*(filename: string): string {.magic: "Slurp".}
|
|||
|
||||
proc gorge*(command: string, input = ""): string {.
|
||||
magic: "StaticExec".} = nil
|
||||
## This is an alias for ``staticExec``.
|
||||
|
||||
proc staticExec*(command: string, input = ""): string {.
|
||||
magic: "StaticExec".} = nil
|
||||
## executes an external process at compile-time.
|
||||
## Executes an external process at compile-time.
|
||||
## if `input` is not an empty string, it will be passed as a standard input
|
||||
## to the executed program.
|
||||
##
|
||||
|
|
@ -2412,7 +2416,9 @@ proc staticExec*(command: string, input = ""): string {.
|
|||
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||
## "\nCompiled on " & staticExec("uname -v")
|
||||
##
|
||||
## ``gorge`` is an alias for ``staticExec``.
|
||||
## ``gorge`` is an alias for ``staticExec``. Note that you can use this proc
|
||||
## inside a pragma like `passC <nimrodc.html#passc-pragma>`_ or `passL
|
||||
## <nimrodc.html#passl-pragma>`_.
|
||||
|
||||
proc `+=`*[T: TOrdinal](x: var T, y: T) {.magic: "Inc", noSideEffect.}
|
||||
## Increments an ordinal
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ when defined(unix) and not defined(useLibzipSrc):
|
|||
when defined(macosx):
|
||||
{.pragma: mydll, dynlib: "libzip2.dylib".}
|
||||
else:
|
||||
{.pragma: mydll, dynlib: "libzip2.so(|.2|.1|.0)".}
|
||||
{.pragma: mydll, dynlib: "libzip(|2).so(|.2|.1|.0)".}
|
||||
else:
|
||||
when defined(unix):
|
||||
{.passl: "-lz".}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue