Check Machin-like formulas: Difference between revisions
m (→{{header|Wren}}: Minor tidy) |
|||
(10 intermediate revisions by 7 users not shown) | |||
Line 41: | Line 41: | ||
<br><br> |
<br><br> |
||
=={{header|BASIC}}== |
|||
==={{header|FreeBASIC}}=== |
|||
{{libheader|GMP}} |
|||
<syntaxhighlight lang="freebasic">' version 07-04-2018 |
|||
' compile with: fbc -s console |
|||
#Include "gmp.bi" |
|||
#Define _a(Q) (@(Q)->_mp_num) 'a |
|||
#Define _b(Q) (@(Q)->_mp_den) 'b |
|||
Data "[1, 1, 2] [1, 1, 3]" |
|||
Data "[2, 1, 3] [1, 1, 7]" |
|||
Data "[4, 1, 5] [-1, 1, 239]" |
|||
Data "[5, 1, 7] [2, 3, 79]" |
|||
Data "[1, 1, 2] [1, 1, 5] [1, 1, 8]" |
|||
Data "[4, 1, 5] [-1, 1, 70] [1, 1, 99]" |
|||
Data "[5, 1, 7] [4, 1, 53] [2, 1, 4443]" |
|||
Data "[6, 1, 8] [2, 1, 57] [1, 1, 239]" |
|||
Data "[8, 1, 10] [-1, 1, 239] [-4, 1, 515]" |
|||
Data "[12, 1, 18] [8, 1, 57] [-5, 1, 239]" |
|||
Data "[16, 1, 21] [3, 1, 239] [4, 3, 1042]" |
|||
Data "[22, 1, 28] [2, 1, 443] [-5, 1, 1393] [-10, 1, 11018]" |
|||
Data "[22, 1, 38] [17, 7, 601] [10, 7, 8149]" |
|||
Data "[44, 1, 57] [7, 1, 239] [-12, 1, 682] [24, 1, 12943]" |
|||
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12943]" |
|||
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12944]" |
|||
Data "" |
|||
Sub work2do (ByRef a As LongInt, f1 As mpq_ptr) |
|||
Dim As LongInt flag = -1 |
|||
Dim As Mpq_ptr x, y, z |
|||
x = Allocate(Len(__mpq_struct)) : Mpq_init(x) |
|||
y = Allocate(Len(__mpq_struct)) : Mpq_init(y) |
|||
z = Allocate(Len(__mpq_struct)) : Mpq_init(z) |
|||
Dim As Mpz_ptr temp1, temp2 |
|||
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1) |
|||
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2) |
|||
mpq_set(y, f1) |
|||
While a > 0 |
|||
If (a And 1) = 1 Then |
|||
If flag = -1 Then |
|||
mpq_set(x, y) |
|||
flag = 0 |
|||
Else |
|||
Mpz_mul(temp1, _a(x), _b(y)) |
|||
Mpz_mul(temp2, _b(x), _a(y)) |
|||
Mpz_add(_a(z), temp1, temp2) |
|||
Mpz_mul(temp1, _b(x), _b(y)) |
|||
Mpz_mul(temp2, _a(x), _a(y)) |
|||
Mpz_sub(_b(z), temp1, temp2) |
|||
mpq_canonicalize(z) |
|||
mpq_set(x, z) |
|||
End If |
|||
End If |
|||
Mpz_mul(temp1, _a(y), _b(y)) |
|||
Mpz_mul(temp2, _b(y), _a(y)) |
|||
Mpz_add(_a(z), temp1, temp2) |
|||
Mpz_mul(temp1, _b(y), _b(y)) |
|||
Mpz_mul(temp2, _a(y), _a(y)) |
|||
Mpz_sub(_b(z), temp1, temp2) |
|||
mpq_canonicalize(z) |
|||
mpq_set(y, z) |
|||
a = a Shr 1 |
|||
Wend |
|||
mpq_set(f1, x) |
|||
End Sub |
|||
' ------=< MAIN >=------ |
|||
Dim As Mpq_ptr f1, f2, f3 |
|||
f1 = Allocate(Len(__mpq_struct)) : Mpq_init(f1) |
|||
f2 = Allocate(Len(__mpq_struct)) : Mpq_init(f2) |
|||
f3 = Allocate(Len(__mpq_struct)) : Mpq_init(f3) |
|||
Dim As Mpz_ptr temp1, temp2 |
|||
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1) |
|||
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2) |
|||
Dim As mpf_ptr float |
|||
float = Allocate(Len(__mpf_struct)) : Mpf_init(float) |
|||
Dim As LongInt m1, a1, b1, flag, t1, t2, t3, t4 |
|||
Dim As String s, s1, s2, s3, sign |
|||
Dim As ZString Ptr zstr |
|||
Do |
|||
Read s |
|||
If s = "" Then Exit Do |
|||
flag = -1 |
|||
While s <> "" |
|||
t1 = InStr(s, "[") +1 |
|||
t2 = InStr(t1, s, ",") +1 |
|||
t3 = InStr(t2, s, ",") +1 |
|||
t4 = InStr(t3, s, "]") |
|||
s1 = Trim(Mid(s, t1, t2 - t1 -1)) |
|||
s2 = Trim(Mid(s, t2, t3 - t2 -1)) |
|||
s3 = Trim(Mid(s, t3, t4 - t3)) |
|||
m1 = Val(s1) |
|||
a1 = Val(s2) |
|||
b1 = Val(s3) |
|||
sign = IIf(m1 < 0, " - ", " + ") |
|||
If m1 < 0 Then a1 = -a1 : m1 = Abs(m1) |
|||
s = Mid(s, t4 +1) |
|||
Print IIf(flag = 0, sign, ""); IIf(m1 = 1, "", Str(m1)); |
|||
Print "Atn("; s2; "/" ;s3; ")"; |
|||
If flag = -1 Then |
|||
flag = 0 |
|||
Mpz_set_si(_a(f1), a1) |
|||
Mpz_set_si(_b(f1), b1) |
|||
If m1 > 1 Then work2do(m1, f1) |
|||
Continue While |
|||
End If |
|||
Mpz_set_si(_a(f2), a1) |
|||
Mpz_set_si(_b(f2), b1) |
|||
If m1 > 1 Then work2do(m1, f2) |
|||
Mpz_mul(temp1, _a(f1), _b(f2)) |
|||
Mpz_mul(temp2, _b(f1), _a(f2)) |
|||
Mpz_add(_a(f3), temp1, temp2) |
|||
Mpz_mul(temp1, _b(f1), _b(f2)) |
|||
Mpz_mul(temp2, _a(f1), _a(f2)) |
|||
Mpz_sub(_b(f3), temp1, temp2) |
|||
mpq_canonicalize(f3) |
|||
mpq_set(f1, f3) |
|||
Wend |
|||
If Mpz_cmp_ui(_b(f1), 1) = 0 AndAlso Mpz_cmp(_a(f1), _b(f1)) = 0 Then |
|||
Print " = 1" |
|||
Else |
|||
Mpf_set_q(float, f1) |
|||
gmp_printf(!" = %.*Ff\n", 15, float) |
|||
End If |
|||
Loop |
|||
' empty keyboard buffer |
|||
While InKey <> "" : Wend |
|||
Print : Print "hit any key to end program" |
|||
Sleep |
|||
End</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Atn(1/2) + Atn(1/3) = 1 |
|||
2Atn(1/3) + Atn(1/7) = 1 |
|||
4Atn(1/5) - Atn(1/239) = 1 |
|||
5Atn(1/7) + 2Atn(3/79) = 1 |
|||
Atn(1/2) + Atn(1/5) + Atn(1/8) = 1 |
|||
4Atn(1/5) - Atn(1/70) + Atn(1/99) = 1 |
|||
5Atn(1/7) + 4Atn(1/53) + 2Atn(1/4443) = 1 |
|||
6Atn(1/8) + 2Atn(1/57) + Atn(1/239) = 1 |
|||
8Atn(1/10) - Atn(1/239) - 4Atn(1/515) = 1 |
|||
12Atn(1/18) + 8Atn(1/57) - 5Atn(1/239) = 1 |
|||
16Atn(1/21) + 3Atn(1/239) + 4Atn(3/1042) = 1 |
|||
22Atn(1/28) + 2Atn(1/443) - 5Atn(1/1393) - 10Atn(1/11018) = 1 |
|||
22Atn(1/38) + 17Atn(7/601) + 10Atn(7/8149) = 1 |
|||
44Atn(1/57) + 7Atn(1/239) - 12Atn(1/682) + 24Atn(1/12943) = 1 |
|||
88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12943) = 1 |
|||
88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12944) = 0.999999188225744</pre> |
|||
==={{header|Visual Basic .NET}}=== |
|||
'''BigRat''' class based on the Arithmetic/Rational#C here at Rosetta Code.<br/> |
|||
The parser here allows for some flexibility in the input text. Case is ignored, and a variable number of spaces are allowed. Atan(), arctan(), atn() are all recognized as valid. If one of those three are not found, a warning will appear. The coefficient need not have a multiplication sign between it and the "arctan()". The left side of the equation must be pi / 4, otherwise a warning will appear. |
|||
<syntaxhighlight lang="vbnet">Imports System.Numerics |
|||
Public Class BigRat ' Big Rational Class constructed with BigIntegers |
|||
Implements IComparable |
|||
Public nu, de As BigInteger |
|||
Public Shared Zero = New BigRat(BigInteger.Zero, BigInteger.One), |
|||
One = New BigRat(BigInteger.One, BigInteger.One) |
|||
Sub New(bRat As BigRat) |
|||
nu = bRat.nu : de = bRat.de |
|||
End Sub |
|||
Sub New(n As BigInteger, d As BigInteger) |
|||
If d = BigInteger.Zero Then _ |
|||
Throw (New Exception(String.Format("tried to set a BigRat with ({0}/{1})", n, d))) |
|||
Dim bi As BigInteger = BigInteger.GreatestCommonDivisor(n, d) |
|||
If bi > BigInteger.One Then n /= bi : d /= bi |
|||
If d < BigInteger.Zero Then n = -n : d = -d |
|||
nu = n : de = d |
|||
End Sub |
|||
Shared Operator -(x As BigRat) As BigRat |
|||
Return New BigRat(-x.nu, x.de) |
|||
End Operator |
|||
Shared Operator +(x As BigRat, y As BigRat) |
|||
Return New BigRat(x.nu * y.de + x.de * y.nu, x.de * y.de) |
|||
End Operator |
|||
Shared Operator -(x As BigRat, y As BigRat) As BigRat |
|||
Return x + (-y) |
|||
End Operator |
|||
Shared Operator *(x As BigRat, y As BigRat) As BigRat |
|||
Return New BigRat(x.nu * y.nu, x.de * y.de) |
|||
End Operator |
|||
Shared Operator /(x As BigRat, y As BigRat) As BigRat |
|||
Return New BigRat(x.nu * y.de, x.de * y.nu) |
|||
End Operator |
|||
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo |
|||
Dim dif As BigRat = New BigRat(nu, de) - obj |
|||
If dif.nu < BigInteger.Zero Then Return -1 |
|||
If dif.nu > BigInteger.Zero Then Return 1 |
|||
Return 0 |
|||
End Function |
|||
Shared Operator =(x As BigRat, y As BigRat) As Boolean |
|||
Return x.CompareTo(y) = 0 |
|||
End Operator |
|||
Shared Operator <>(x As BigRat, y As BigRat) As Boolean |
|||
Return x.CompareTo(y) <> 0 |
|||
End Operator |
|||
Overrides Function ToString() As String |
|||
If de = BigInteger.One Then Return nu.ToString |
|||
Return String.Format("({0}/{1})", nu, de) |
|||
End Function |
|||
Shared Function Combine(a As BigRat, b As BigRat) As BigRat |
|||
Return (a + b) / (BigRat.One - (a * b)) |
|||
End Function |
|||
End Class |
|||
Public Structure Term ' coefficent, BigRational construction for each term |
|||
Dim c As Integer, br As BigRat |
|||
Sub New(cc As Integer, bigr As BigRat) |
|||
c = cc : br = bigr |
|||
End Sub |
|||
End Structure |
|||
Module Module1 |
|||
Function Eval(c As Integer, x As BigRat) As BigRat |
|||
If c = 1 Then Return x Else If c < 0 Then Return Eval(-c, -x) |
|||
Dim hc As Integer = c \ 2 |
|||
Return BigRat.Combine(Eval(hc, x), Eval(c - hc, x)) |
|||
End Function |
|||
Function Sum(terms As List(Of Term)) As BigRat |
|||
If terms.Count = 1 Then Return Eval(terms(0).c, terms(0).br) |
|||
Dim htc As Integer = terms.Count / 2 |
|||
Return BigRat.Combine(Sum(terms.Take(htc).ToList), Sum(terms.Skip(htc).ToList)) |
|||
End Function |
|||
Function ParseLine(ByVal s As String) As List(Of Term) |
|||
ParseLine = New List(Of Term) : Dim t As String = s.ToLower, p As Integer, x As New Term(1, BigRat.Zero) |
|||
While t.Contains(" ") : t = t.Replace(" ", "") : End While |
|||
p = t.IndexOf("pi/4=") : If p < 0 Then _ |
|||
Console.WriteLine("warning: tan(left side of equation) <> 1") : ParseLine.Add(x) : Exit Function |
|||
t = t.Substring(p + 5) |
|||
For Each item As String In t.Split(")") |
|||
If item.Length > 5 Then |
|||
If (Not item.Contains("tan") OrElse item.IndexOf("a") < 0 OrElse |
|||
item.IndexOf("a") > item.IndexOf("tan")) AndAlso Not item.Contains("atn") Then |
|||
Console.WriteLine("warning: a term is mising a valid arctangent identifier on the right side of the equation: [{0})]", item) |
|||
ParseLine = New List(Of Term) : ParseLine.Add(New Term(1, BigRat.Zero)) : Exit Function |
|||
End If |
|||
x.c = 1 : x.br = New BigRat(BigRat.One) |
|||
p = item.IndexOf("/") : If p > 0 Then |
|||
x.br.de = UInt64.Parse(item.Substring(p + 1)) |
|||
item = item.Substring(0, p) |
|||
p = item.IndexOf("(") : If p > 0 Then |
|||
x.br.nu = UInt64.Parse(item.Substring(p + 1)) |
|||
p = item.IndexOf("a") : If p > 0 Then |
|||
Integer.TryParse(item.Substring(0, p).Replace("*", ""), x.c) |
|||
If x.c = 0 Then x.c = 1 |
|||
If item.Contains("-") AndAlso x.c > 0 Then x.c = -x.c |
|||
End If |
|||
ParseLine.Add(x) |
|||
End If |
|||
End If |
|||
End If |
|||
Next |
|||
End Function |
|||
Sub Main(ByVal args As String()) |
|||
Dim nl As String = vbLf |
|||
For Each item In ("pi/4 = ATan(1 / 2) + ATan(1/3)" & nl & |
|||
"pi/4 = 2Atan(1/3) + ATan(1/7)" & nl & |
|||
"pi/4 = 4ArcTan(1/5) - ATan(1 / 239)" & nl & |
|||
"pi/4 = 5arctan(1/7) + 2 * atan(3/79)" & nl & |
|||
"Pi/4 = 5ATan(29/278) + 7*ATan(3/79)" & nl & |
|||
"pi/4 = atn(1/2) + ATan(1/5) + ATan(1/8)" & nl & |
|||
"PI/4 = 4ATan(1/5) - Atan(1/70) + ATan(1/99)" & nl & |
|||
"pi /4 = 5*ATan(1/7) + 4 ATan(1/53) + 2ATan(1/4443)" & nl & |
|||
"pi / 4 = 6ATan(1/8) + 2arctangent(1/57) + ATan(1/239)" & nl & |
|||
"pi/ 4 = 8ATan(1/10) - ATan(1/239) - 4ATan(1/515)" & nl & |
|||
"pi/4 = 12ATan(1/18) + 8ATan(1/57) - 5ATan(1/239)" & nl & |
|||
"pi/4 = 16 * ATan(1/21) + 3ATan(1/239) + 4ATan(3/1042)" & nl & |
|||
"pi/4 = 22ATan(1/28) + 2ATan(1/443) - 5ATan(1/1393) - 10 ATan( 1 / 11018 )" & nl & |
|||
"pi/4 = 22ATan(1/38) + 17ATan(7/601) + 10ATan(7 / 8149)" & nl & |
|||
"pi/4 = 44ATan(1/57) + 7ATan(1/239) - 12ATan(1/682) + 24ATan(1/12943)" & nl & |
|||
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12943)" & nl & |
|||
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12944)").Split(nl) |
|||
Console.WriteLine("{0}: {1}", If(Sum(ParseLine(item)) = BigRat.One, "Pass", "Fail"), item) |
|||
Next |
|||
End Sub |
|||
End Module</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Pass: pi/4 = ATan(1 / 2) + ATan(1/3) |
|||
Pass: pi/4 = 2Atan(1/3) + ATan(1/7) |
|||
Pass: pi/4 = 4ArcTan(1/5) - ATan(1 / 239) |
|||
Pass: pi/4 = 5arctan(1/7) + 2 * atan(3/79) |
|||
Pass: pi/4 = 5ATan(29/278) + 7*ATan(3/79) |
|||
Pass: pi/4 = atn(1/2) + ATan(1/5) + ATan(1/8) |
|||
Pass: pi/4 = 4ATan(1/5) - Atan(1/70) + ATan(1/99) |
|||
Pass: pi /4 = 5*ATan(1/7) + 4 ATan(1/53) + 2ATan(1/4443) |
|||
Pass: pi / 4 = 6ATan(1/8) + 2arctangent(1/57) + ATan(1/239) |
|||
Pass: pi/ 4 = 8ATan(1/10) - ATan(1/239) - 4ATan(1/515) |
|||
Pass: pi/4 = 12ATan(1/18) + 8ATan(1/57) - 5ATan(1/239) |
|||
Pass: pi/4 = 16 * ATan(1/21) + 3ATan(1/239) + 4ATan(3/1042) |
|||
Pass: pi/4 = 22ATan(1/28) + 2ATan(1/443) - 5ATan(1/1393) - 10 ATan( 1 / 11018 ) |
|||
Pass: pi/4 = 22ATan(1/38) + 17ATan(7/601) + 10ATan(7 / 8149) |
|||
Pass: pi/4 = 44ATan(1/57) + 7ATan(1/239) - 12ATan(1/682) + 24ATan(1/12943) |
|||
Pass: pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12943) |
|||
Fail: pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12944)</pre> |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
Clojure automatically handles ratio of numbers as fractions |
Clojure automatically handles ratio of numbers as fractions |
||
{{trans|Go}} |
{{trans|Go}} |
||
< |
<syntaxhighlight lang="lisp">(ns tanevaulator |
||
(:gen-class)) |
(:gen-class)) |
||
Line 97: | Line 421: | ||
" Display results " |
" Display results " |
||
(println "tan " q " = "(tans q))) |
(println "tan " q " = "(tans q))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Output}} |
{{Output}} |
||
<pre> |
<pre> |
||
Line 120: | Line 444: | ||
(equals 0.9999991882257445) |
(equals 0.9999991882257445) |
||
</pre> |
</pre> |
||
=={{header|D}}== |
=={{header|D}}== |
||
This uses the module of the Arithmetic Rational Task. |
This uses the module of the Arithmetic Rational Task. |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="d">import std.stdio, std.regex, std.conv, std.string, std.range, |
||
arithmetic_rational; |
arithmetic_rational; |
||
Line 194: | Line 517: | ||
writefln("%5s: %s", ans == 1 ? "OK" : "ERROR", eqn); |
writefln("%5s: %s", ans == 1 ? "OK" : "ERROR", eqn); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> OK: pi/4 = arctan(1/2) + arctan(1/3) |
<pre> OK: pi/4 = arctan(1/2) + arctan(1/3) |
||
Line 213: | Line 536: | ||
OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) |
OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) |
||
ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)</pre> |
ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)</pre> |
||
=={{header|EchoLisp}}== |
=={{header|EchoLisp}}== |
||
< |
<syntaxhighlight lang="scheme"> |
||
(lib 'math) |
(lib 'math) |
||
(lib 'match) |
(lib 'match) |
||
Line 274: | Line 596: | ||
(writeln '❌ f '➽ (reduce f) )))) |
(writeln '❌ f '➽ (reduce f) )))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang="scheme"> |
||
(define machins |
(define machins |
||
Line 321: | Line 643: | ||
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12944)))) ➽ 0.9999991882257442 |
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12944)))) ➽ 0.9999991882257442 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
< |
<syntaxhighlight lang="factor">USING: combinators formatting kernel locals math sequences ; |
||
IN: rosetta-code.machin |
IN: rosetta-code.machin |
||
Line 362: | Line 683: | ||
} [ dup tans "tan %u = %u\n" printf ] each ; |
} [ dup tans "tan %u = %u\n" printf ] each ; |
||
MAIN: machin</ |
MAIN: machin</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 394: | Line 715: | ||
} = 10092...08223/10092...39711 |
} = 10092...08223/10092...39711 |
||
</pre> |
</pre> |
||
=={{header|FreeBASIC}}== |
|||
{{libheader|GMP}} |
|||
<lang freebasic>' version 07-04-2018 |
|||
' compile with: fbc -s console |
|||
#Include "gmp.bi" |
|||
#Define _a(Q) (@(Q)->_mp_num) 'a |
|||
#Define _b(Q) (@(Q)->_mp_den) 'b |
|||
Data "[1, 1, 2] [1, 1, 3]" |
|||
Data "[2, 1, 3] [1, 1, 7]" |
|||
Data "[4, 1, 5] [-1, 1, 239]" |
|||
Data "[5, 1, 7] [2, 3, 79]" |
|||
Data "[1, 1, 2] [1, 1, 5] [1, 1, 8]" |
|||
Data "[4, 1, 5] [-1, 1, 70] [1, 1, 99]" |
|||
Data "[5, 1, 7] [4, 1, 53] [2, 1, 4443]" |
|||
Data "[6, 1, 8] [2, 1, 57] [1, 1, 239]" |
|||
Data "[8, 1, 10] [-1, 1, 239] [-4, 1, 515]" |
|||
Data "[12, 1, 18] [8, 1, 57] [-5, 1, 239]" |
|||
Data "[16, 1, 21] [3, 1, 239] [4, 3, 1042]" |
|||
Data "[22, 1, 28] [2, 1, 443] [-5, 1, 1393] [-10, 1, 11018]" |
|||
Data "[22, 1, 38] [17, 7, 601] [10, 7, 8149]" |
|||
Data "[44, 1, 57] [7, 1, 239] [-12, 1, 682] [24, 1, 12943]" |
|||
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12943]" |
|||
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12944]" |
|||
Data "" |
|||
Sub work2do (ByRef a As LongInt, f1 As mpq_ptr) |
|||
Dim As LongInt flag = -1 |
|||
Dim As Mpq_ptr x, y, z |
|||
x = Allocate(Len(__mpq_struct)) : Mpq_init(x) |
|||
y = Allocate(Len(__mpq_struct)) : Mpq_init(y) |
|||
z = Allocate(Len(__mpq_struct)) : Mpq_init(z) |
|||
Dim As Mpz_ptr temp1, temp2 |
|||
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1) |
|||
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2) |
|||
mpq_set(y, f1) |
|||
While a > 0 |
|||
If (a And 1) = 1 Then |
|||
If flag = -1 Then |
|||
mpq_set(x, y) |
|||
flag = 0 |
|||
Else |
|||
Mpz_mul(temp1, _a(x), _b(y)) |
|||
Mpz_mul(temp2, _b(x), _a(y)) |
|||
Mpz_add(_a(z), temp1, temp2) |
|||
Mpz_mul(temp1, _b(x), _b(y)) |
|||
Mpz_mul(temp2, _a(x), _a(y)) |
|||
Mpz_sub(_b(z), temp1, temp2) |
|||
mpq_canonicalize(z) |
|||
mpq_set(x, z) |
|||
End If |
|||
End If |
|||
Mpz_mul(temp1, _a(y), _b(y)) |
|||
Mpz_mul(temp2, _b(y), _a(y)) |
|||
Mpz_add(_a(z), temp1, temp2) |
|||
Mpz_mul(temp1, _b(y), _b(y)) |
|||
Mpz_mul(temp2, _a(y), _a(y)) |
|||
Mpz_sub(_b(z), temp1, temp2) |
|||
mpq_canonicalize(z) |
|||
mpq_set(y, z) |
|||
a = a Shr 1 |
|||
Wend |
|||
mpq_set(f1, x) |
|||
End Sub |
|||
' ------=< MAIN >=------ |
|||
Dim As Mpq_ptr f1, f2, f3 |
|||
f1 = Allocate(Len(__mpq_struct)) : Mpq_init(f1) |
|||
f2 = Allocate(Len(__mpq_struct)) : Mpq_init(f2) |
|||
f3 = Allocate(Len(__mpq_struct)) : Mpq_init(f3) |
|||
Dim As Mpz_ptr temp1, temp2 |
|||
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1) |
|||
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2) |
|||
Dim As mpf_ptr float |
|||
float = Allocate(Len(__mpf_struct)) : Mpf_init(float) |
|||
Dim As LongInt m1, a1, b1, flag, t1, t2, t3, t4 |
|||
Dim As String s, s1, s2, s3, sign |
|||
Dim As ZString Ptr zstr |
|||
Do |
|||
Read s |
|||
If s = "" Then Exit Do |
|||
flag = -1 |
|||
While s <> "" |
|||
t1 = InStr(s, "[") +1 |
|||
t2 = InStr(t1, s, ",") +1 |
|||
t3 = InStr(t2, s, ",") +1 |
|||
t4 = InStr(t3, s, "]") |
|||
s1 = Trim(Mid(s, t1, t2 - t1 -1)) |
|||
s2 = Trim(Mid(s, t2, t3 - t2 -1)) |
|||
s3 = Trim(Mid(s, t3, t4 - t3)) |
|||
m1 = Val(s1) |
|||
a1 = Val(s2) |
|||
b1 = Val(s3) |
|||
sign = IIf(m1 < 0, " - ", " + ") |
|||
If m1 < 0 Then a1 = -a1 : m1 = Abs(m1) |
|||
s = Mid(s, t4 +1) |
|||
Print IIf(flag = 0, sign, ""); IIf(m1 = 1, "", Str(m1)); |
|||
Print "Atn("; s2; "/" ;s3; ")"; |
|||
If flag = -1 Then |
|||
flag = 0 |
|||
Mpz_set_si(_a(f1), a1) |
|||
Mpz_set_si(_b(f1), b1) |
|||
If m1 > 1 Then work2do(m1, f1) |
|||
Continue While |
|||
End If |
|||
Mpz_set_si(_a(f2), a1) |
|||
Mpz_set_si(_b(f2), b1) |
|||
If m1 > 1 Then work2do(m1, f2) |
|||
Mpz_mul(temp1, _a(f1), _b(f2)) |
|||
Mpz_mul(temp2, _b(f1), _a(f2)) |
|||
Mpz_add(_a(f3), temp1, temp2) |
|||
Mpz_mul(temp1, _b(f1), _b(f2)) |
|||
Mpz_mul(temp2, _a(f1), _a(f2)) |
|||
Mpz_sub(_b(f3), temp1, temp2) |
|||
mpq_canonicalize(f3) |
|||
mpq_set(f1, f3) |
|||
Wend |
|||
If Mpz_cmp_ui(_b(f1), 1) = 0 AndAlso Mpz_cmp(_a(f1), _b(f1)) = 0 Then |
|||
Print " = 1" |
|||
Else |
|||
Mpf_set_q(float, f1) |
|||
gmp_printf(!" = %.*Ff\n", 15, float) |
|||
End If |
|||
Loop |
|||
' empty keyboard buffer |
|||
While InKey <> "" : Wend |
|||
Print : Print "hit any key to end program" |
|||
Sleep |
|||
End</lang> |
|||
{{out}} |
|||
<pre>Atn(1/2) + Atn(1/3) = 1 |
|||
2Atn(1/3) + Atn(1/7) = 1 |
|||
4Atn(1/5) - Atn(1/239) = 1 |
|||
5Atn(1/7) + 2Atn(3/79) = 1 |
|||
Atn(1/2) + Atn(1/5) + Atn(1/8) = 1 |
|||
4Atn(1/5) - Atn(1/70) + Atn(1/99) = 1 |
|||
5Atn(1/7) + 4Atn(1/53) + 2Atn(1/4443) = 1 |
|||
6Atn(1/8) + 2Atn(1/57) + Atn(1/239) = 1 |
|||
8Atn(1/10) - Atn(1/239) - 4Atn(1/515) = 1 |
|||
12Atn(1/18) + 8Atn(1/57) - 5Atn(1/239) = 1 |
|||
16Atn(1/21) + 3Atn(1/239) + 4Atn(3/1042) = 1 |
|||
22Atn(1/28) + 2Atn(1/443) - 5Atn(1/1393) - 10Atn(1/11018) = 1 |
|||
22Atn(1/38) + 17Atn(7/601) + 10Atn(7/8149) = 1 |
|||
44Atn(1/57) + 7Atn(1/239) - 12Atn(1/682) + 24Atn(1/12943) = 1 |
|||
88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12943) = 1 |
|||
88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12944) = 0.999999188225744</pre> |
|||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
The formula is entered as a list of pairs [k, x], where each pair means k*atan(x), and all the terms in the list are summed. Like most other solutions, the program will only check that the tangent of the resulting sum is 1. For instance, <code>Check([[5, 1/2], [5, 1/3]]);</code> returns also <code>true</code>, though the result is 5pi/4. |
The formula is entered as a list of pairs [k, x], where each pair means k*atan(x), and all the terms in the list are summed. Like most other solutions, the program will only check that the tangent of the resulting sum is 1. For instance, <code>Check([[5, 1/2], [5, 1/3]]);</code> returns also <code>true</code>, though the result is 5pi/4. |
||
< |
<syntaxhighlight lang="gap">TanPlus := function(a, b) |
||
return (a + b) / (1 - a * b); |
return (a + b) / (1 - a * b); |
||
end; |
end; |
||
Line 614: | Line 761: | ||
[[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12943]]], Check); |
[[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12943]]], Check); |
||
Check([[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]);</ |
Check([[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]);</syntaxhighlight> |
||
=={{header|Go}}== |
=={{header|Go}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 681: | Line 827: | ||
r := new(big.Rat) |
r := new(big.Rat) |
||
return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b))) |
return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b))) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Last line edited to show only most significant digits of fraction which is near, but not exactly equal to 1. |
Last line edited to show only most significant digits of fraction which is near, but not exactly equal to 1. |
||
Line 704: | Line 850: | ||
100928883... |
100928883... |
||
</pre> |
</pre> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Data.Ratio |
||
import Data.List (foldl') |
import Data.List (foldl') |
||
Line 736: | Line 881: | ||
putStr "\nnot Machin: "; print not_machin |
putStr "\nnot Machin: "; print not_machin |
||
print (tans not_machin)</ |
print (tans not_machin)</syntaxhighlight> |
||
A crazier way to do the above, exploiting the built-in exponentiation algorithms: |
A crazier way to do the above, exploiting the built-in exponentiation algorithms: |
||
< |
<syntaxhighlight lang="haskell">import Data.Ratio |
||
-- Private type. Do not use outside of the tans function |
-- Private type. Do not use outside of the tans function |
||
Line 772: | Line 917: | ||
putStr "\nnot Machin: "; print not_machin |
putStr "\nnot Machin: "; print not_machin |
||
print (tans not_machin)</ |
print (tans not_machin)</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
'''Solution''':< |
'''Solution''':<syntaxhighlight lang="j"> machin =: 1r4p1 = [: +/ ({. * _3 o. %/@:}.)"1@:x:</syntaxhighlight> |
||
'''Example''' (''test cases from task description''):< |
'''Example''' (''test cases from task description''):<syntaxhighlight lang="j"> R =: <@:(0&".);._2 ];._2 noun define |
||
1 1 2 |
1 1 2 |
||
1 1 3 |
1 1 3 |
||
Line 844: | Line 987: | ||
machin&> R |
machin&> R |
||
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</ |
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</syntaxhighlight> |
||
'''Example''' (''counterexample''):< |
'''Example''' (''counterexample''):<syntaxhighlight lang="j"> counterExample=. 12944 (<_1;_1)} >{:R |
||
counterExample NB. Same as final test case with 12943 incremented to 12944 |
counterExample NB. Same as final test case with 12943 incremented to 12944 |
||
88 1 172 |
88 1 172 |
||
Line 853: | Line 996: | ||
68 1 12944 |
68 1 12944 |
||
machin counterExample |
machin counterExample |
||
0</ |
0</syntaxhighlight> |
||
'''Notes''': The function <tt>machin</tt> compares the results of each formula to π/4 (expressed as <tt>1r4p1</tt> in J's numeric notation). The first example above shows the results of these comparisons for each formula (with 1 for true and 0 for false). In J, arctan is expressed as <tt>_3 o. ''values''</tt> and the function <tt>x:</tt> coerces values to exact representation; thereafter J will maintain exactness throughout its calculations, as long as it can. |
'''Notes''': The function <tt>machin</tt> compares the results of each formula to π/4 (expressed as <tt>1r4p1</tt> in J's numeric notation). The first example above shows the results of these comparisons for each formula (with 1 for true and 0 for false). In J, arctan is expressed as <tt>_3 o. ''values''</tt> and the function <tt>x:</tt> coerces values to exact representation; thereafter J will maintain exactness throughout its calculations, as long as it can. |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
Read formula from file. Parse and evaluate formula. |
Read formula from file. Parse and evaluate formula. |
||
Implement Fraction class to support task. |
Implement Fraction class to support task. |
||
< |
<syntaxhighlight lang="java"> |
||
import java.io.BufferedReader; |
import java.io.BufferedReader; |
||
import java.io.File; |
import java.io.File; |
||
Line 1,006: | Line 1,148: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 1,029: | Line 1,171: | ||
</pre> |
</pre> |
||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia"> |
||
using AbstractAlgebra # implements arbitrary precision rationals |
using AbstractAlgebra # implements arbitrary precision rationals |
||
Line 1,069: | Line 1,210: | ||
runtestmats() |
runtestmats() |
||
</ |
</syntaxhighlight> {{output}} <pre> |
||
Testing matrices: |
Testing matrices: |
||
Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(1, 1//2), (1, 1//3)] = 1//1 |
Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(1, 1//2), (1, 1//3)] = 1//1 |
||
Line 1,077: | Line 1,218: | ||
Verified as false: tan Tuple{BigInt,Rational{BigInt}}[(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12944)] = 1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223//1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711 |
Verified as false: tan Tuple{BigInt,Rational{BigInt}}[(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12944)] = 1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223//1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711 |
||
</pre> |
</pre> |
||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
As the JVM and Kotlin standard libraries lack a BigRational class, I've written one which just provides sufficient functionality to complete this task: |
As the JVM and Kotlin standard libraries lack a BigRational class, I've written one which just provides sufficient functionality to complete this task: |
||
< |
<syntaxhighlight lang="scala">// version 1.1.3 |
||
import java.math.BigInteger |
import java.math.BigInteger |
||
Line 1,211: | Line 1,351: | ||
println(")") |
println(")") |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,233: | Line 1,373: | ||
false << 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944)) |
false << 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944)) |
||
</pre> |
</pre> |
||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
||
<lang>Tan[ArcTan[1/2] + ArcTan[1/3]] == 1 |
<syntaxhighlight lang="text">Tan[ArcTan[1/2] + ArcTan[1/3]] == 1 |
||
Tan[2 ArcTan[1/3] + ArcTan[1/7]] == 1 |
Tan[2 ArcTan[1/3] + ArcTan[1/7]] == 1 |
||
Tan[4 ArcTan[1/5] - ArcTan[1/239]] == 1 |
Tan[4 ArcTan[1/5] - ArcTan[1/239]] == 1 |
||
Line 1,255: | Line 1,394: | ||
44 ArcTan[1/5357] + 68 ArcTan[1/12943]] == 1 |
44 ArcTan[1/5357] + 68 ArcTan[1/12943]] == 1 |
||
Tan[88 ArcTan[1/172] + 51 ArcTan[1/239] + 32 ArcTan[1/682] + |
Tan[88 ArcTan[1/172] + 51 ArcTan[1/239] + 32 ArcTan[1/682] + |
||
44 ArcTan[1/5357] + 68 ArcTan[1/12944]] == 1</ |
44 ArcTan[1/5357] + 68 ArcTan[1/12944]] == 1</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 1,291: | Line 1,430: | ||
False</pre> |
False</pre> |
||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang="maxima">trigexpand:true$ |
||
is(tan(atan(1/2)+atan(1/3))=1); |
is(tan(atan(1/2)+atan(1/3))=1); |
||
is(tan(2*atan(1/3)+atan(1/7))=1); |
is(tan(2*atan(1/3)+atan(1/7))=1); |
||
Line 1,310: | Line 1,448: | ||
is(tan(44*atan(1/57)+7*atan(1/239)-12*atan(1/682)+24*atan(1/12943))=1); |
is(tan(44*atan(1/57)+7*atan(1/239)-12*atan(1/682)+24*atan(1/12943))=1); |
||
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12943))=1); |
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12943))=1); |
||
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12944))=1);</ |
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12944))=1);</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>(%i2) |
<pre>(%i2) |
||
Line 1,346: | Line 1,484: | ||
(%i18) |
(%i18) |
||
(%o18) false</pre> |
(%o18) false</pre> |
||
=={{header|Nim}}== |
|||
{{libheader|bignum}} |
|||
The most important part of our program is the formula parser which proceeds to a full syntactical validation. The parser builds an expression which is a sequence of terms, a term being itself composed of a factor and a fraction (the argument to arctan). |
|||
<syntaxhighlight lang="nim">import bignum |
|||
type |
|||
# Description of a term. |
|||
Term = object |
|||
factor: int # Multiplier (may be negative). |
|||
fract: Rat # Argument of arc tangent. |
|||
Expression = seq[Term] |
|||
# Rational 1. |
|||
let One = newRat(1) |
|||
#################################################################################################### |
|||
# Formula parser. |
|||
type |
|||
# Possible tokens for parsing. |
|||
Token = enum tkPi, tkArctan, tkNumber, tkEqual, tkAdd, tkSub, |
|||
tkMul, tkDiv, tkLPar, tkRPar, tkError, tkEnd |
|||
# Lexer description. |
|||
Lexer = object |
|||
line: string # The line to parse. |
|||
pos: Natural # Current position of lexer. |
|||
token: Token # Current token. |
|||
value: Natural # Associated value (for numbers). |
|||
# Exception raised if an error is found. |
|||
SyntaxError = object of CatchableError |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc initLexer(line: string): Lexer = |
|||
## Create and initialize a lexer. |
|||
result.line = line |
|||
result.pos = 0 |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc parseName(lexer: var Lexer; pos: Natural) = |
|||
## Parse a name. |
|||
# Build the name. |
|||
var pos = pos |
|||
var name = "" |
|||
while pos < lexer.line.len and (let c = lexer.line[pos]; c) in 'a'..'z': |
|||
name.add(c) |
|||
inc pos |
|||
# Update lexer state. |
|||
lexer.token = if name == "arctan": tkArctan |
|||
elif name == "pi": tkPi |
|||
else: tkError |
|||
lexer.pos = pos |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc parseNumber(lexer: var Lexer; pos: Natural) = |
|||
## Parse a number. |
|||
# Build the number. |
|||
var pos = pos |
|||
var value = 0 |
|||
while pos < lexer.line.len and (let c = lexer.line[pos]; c) in '0'..'9': |
|||
value = 10 * value + ord(c) - ord('0') |
|||
inc pos |
|||
# Update lexer state. |
|||
lexer.token = tkNumber |
|||
lexer.value = value |
|||
lexer.pos = pos |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc getNextToken(lexer: var Lexer) = |
|||
## Find next token. |
|||
var pos = lexer.pos |
|||
var token: Token |
|||
while pos < lexer.line.len and lexer.line[pos] == ' ': inc pos |
|||
if pos == lexer.line.len: |
|||
# Reached end of string. |
|||
lexer.pos = pos |
|||
lexer.token = tkEnd |
|||
return |
|||
# Find token. |
|||
case lexer.line[pos] |
|||
of '=': token = tkEqual |
|||
of '+': token = tkAdd |
|||
of '-': token = tkSub |
|||
of '*': token = tkMul |
|||
of '/': token = tkDiv |
|||
of '(': token = tkLPar |
|||
of ')': token = tkRPar |
|||
of 'a'..'z': |
|||
lexer.parseName(pos) |
|||
return |
|||
of '0'..'9': |
|||
lexer.parseNumber(pos) |
|||
return |
|||
else: token = tkError |
|||
# Update lexer state. |
|||
lexer.pos = pos + 1 |
|||
lexer.token = token |
|||
#--------------------------------------------------------------------------------------------------- |
|||
template syntaxError(message: string) = |
|||
## Raise a syntax error exception. |
|||
raise newException(SyntaxError, message) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc parseFraction(lexer: var Lexer): Rat = |
|||
## Parse a fraction: number / number. |
|||
lexer.getNextToken() |
|||
if lexer.token != tkNumber: |
|||
syntaxError("number expected.") |
|||
let num = lexer.value |
|||
lexer.getNextToken() |
|||
if lexer.token != tkDiv: |
|||
syntaxError("“/” expected.") |
|||
lexer.getNextToken() |
|||
if lexer.token != tkNumber: |
|||
syntaxError("number expected") |
|||
if lexer.value == 0: |
|||
raise newException(ValueError, "null denominator.") |
|||
let den = lexer.value |
|||
result = newRat(num, den) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc parseTerm(lexer: var Lexer): Term = |
|||
## Parse a term: factor * arctan(fraction) or arctan(fraction). |
|||
lexer.getNextToken() |
|||
# Parse factor. |
|||
if lexer.token == tkNumber: |
|||
result.factor = lexer.value |
|||
lexer.getNextToken |
|||
if lexer.token != tkMul: |
|||
syntaxError("“*” expected.") |
|||
lexer.getNextToken() |
|||
else: |
|||
result.factor = 1 |
|||
# Parse arctan. |
|||
if lexer.token != tkArctan: |
|||
syntaxError("“arctan” expected.") |
|||
lexer.getNextToken() |
|||
if lexer.token != tkLPar: |
|||
syntaxError("“(” expected.") |
|||
result.fract = lexer.parseFraction() |
|||
lexer.getNextToken() |
|||
if lexer.token != tkRPar: |
|||
syntaxError("“)” expected.") |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc parse(line: string): Expression = |
|||
## Parse a formula. |
|||
var lexer = initLexer(line) |
|||
lexer.getNextToken() |
|||
if lexer.token != tkPi: |
|||
syntaxError("pi symbol expected.") |
|||
lexer.getNextToken() |
|||
if lexer.token != tkDiv: |
|||
syntaxError("'/' expected.") |
|||
lexer.getNextToken() |
|||
if lexer.token != tkNumber: |
|||
syntaxError("number expected.") |
|||
if lexer.value != 4: |
|||
raise newException(ValueError, "value 4 expected.") |
|||
lexer.getNextToken() |
|||
if lexer.token != tkEqual: |
|||
syntaxError("“=” expected.") |
|||
result.add(lexer.parseTerm()) |
|||
lexer.getNextToken() |
|||
# Parse the next terms. |
|||
while (let token = lexer.token; token) in {tkAdd, tkSub}: |
|||
var term = lexer.parseTerm() |
|||
if token == tkSub: |
|||
term.factor = -term.factor |
|||
result.add(term) |
|||
lexer.getNextToken() |
|||
if lexer.token != tkEnd: |
|||
syntaxError("invalid characters at end of formula.") |
|||
#################################################################################################### |
|||
# Evaluator. |
|||
proc tangent(factor: int; fract: Rat): Rat = |
|||
## Compute the tangent of "factor * arctan(fract)". |
|||
if factor == 1: |
|||
return fract |
|||
if factor < 0: |
|||
return -tangent(-factor, fract) |
|||
# Split in two parts. |
|||
let n = factor div 2 |
|||
let a = tangent(n, fract) |
|||
let b = tangent(factor - n, fract) |
|||
result = (a + b) / (One - a * b) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc tangent(expr: Expression): Rat = |
|||
## Compute the tangent of a sum of terms. |
|||
if expr.len == 1: |
|||
result = tangent(expr[0].factor, expr[0].fract) |
|||
else: |
|||
# Split in two parts. |
|||
let a = tangent(expr[0..<(expr.len div 2)]) |
|||
let b = tangent(expr[(expr.len div 2)..^1]) |
|||
result = (a + b) / (One - a * b) |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
when isMainModule: |
|||
const Formulas = [ |
|||
"pi/4 = arctan(1/2) + arctan(1/3)", |
|||
"pi/4 = 2*arctan(1/3) + arctan(1/7)", |
|||
"pi/4 = 4*arctan(1/5) - arctan(1/239)", |
|||
"pi/4 = 5*arctan(1/7) + 2*arctan(3/79)", |
|||
"pi/4 = 5*arctan(29/278) + 7*arctan(3/79)", |
|||
"pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)", |
|||
"pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)", |
|||
"pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)", |
|||
"pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)", |
|||
"pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)", |
|||
"pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)", |
|||
"pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)", |
|||
"pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)", |
|||
"pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)", |
|||
"pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)", |
|||
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)", |
|||
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)"] |
|||
for formula in Formulas: |
|||
let expr = formula.parse() |
|||
let value = tangent(expr) |
|||
if value == 1: |
|||
echo "True: ", formula |
|||
else: |
|||
echo "False: ", formula |
|||
echo "Tangent of the right expression is about ", value.toFloat</syntaxhighlight> |
|||
{{out}} |
|||
<pre>True: pi/4 = arctan(1/2) + arctan(1/3) |
|||
True: pi/4 = 2*arctan(1/3) + arctan(1/7) |
|||
True: pi/4 = 4*arctan(1/5) - arctan(1/239) |
|||
True: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) |
|||
True: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) |
|||
True: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) |
|||
True: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) |
|||
True: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) |
|||
True: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) |
|||
True: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) |
|||
True: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) |
|||
True: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) |
|||
True: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) |
|||
True: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) |
|||
True: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) |
|||
True: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) |
|||
False: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) |
|||
Tangent of the right expression is about 0.9999991882257444</pre> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">open Num;; (* use exact rationals for results *) |
||
let tadd p q = (p +/ q) // ((Int 1) -/ (p */ q)) in |
let tadd p q = (p +/ q) // ((Int 1) -/ (p */ q)) in |
||
Line 1,399: | Line 1,824: | ||
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12943)]); |
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12943)]); |
||
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12944)]) |
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12944)]) |
||
]</ |
]</syntaxhighlight> |
||
Compile with |
Compile with |
||
Line 1,443: | Line 1,868: | ||
tan(RHS) is not one |
tan(RHS) is not one |
||
</pre> |
</pre> |
||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
< |
<syntaxhighlight lang="oorexx">/*REXX ---------------------------------------------------------------- |
||
* 09.04.2014 Walter Pachl the REXX solution adapted for ooRexx |
* 09.04.2014 Walter Pachl the REXX solution adapted for ooRexx |
||
* which provides a function package rxMath |
* which provides a function package rxMath |
||
Line 1,473: | Line 1,897: | ||
end /*j*/ /* [?] show OK | bad, formula. */ |
end /*j*/ /* [?] show OK | bad, formula. */ |
||
::requires rxmath library |
::requires rxmath library |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> OK: pi/4=rxCalcarctan(1/2,16,R)+rxCalcarctan(1/3,16,R) |
<pre> OK: pi/4=rxCalcarctan(1/2,16,R)+rxCalcarctan(1/3,16,R) |
||
Line 1,492: | Line 1,916: | ||
OK: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12943,16,R) |
OK: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12943,16,R) |
||
bad: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12944,16,R)</pre> |
bad: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12944,16,R)</pre> |
||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
< |
<syntaxhighlight lang="parigp">tanEval(coef, f)={ |
||
if (coef <= 1, return(if(coef<1,-tanEval(-coef, f),f))); |
if (coef <= 1, return(if(coef<1,-tanEval(-coef, f),f))); |
||
my(a=tanEval(coef\2, f), b=tanEval(coef-coef\2, f)); |
my(a=tanEval(coef\2, f), b=tanEval(coef-coef\2, f)); |
||
Line 1,524: | Line 1,947: | ||
test([[44,1/57],[7,1/239],[-12,1/682],[24,1/12943]]); |
test([[44,1/57],[7,1/239],[-12,1/682],[24,1/12943]]); |
||
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12943]]); |
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12943]]); |
||
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12944]]);</ |
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12944]]);</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>OK |
<pre>OK |
||
Line 1,543: | Line 1,966: | ||
OK |
OK |
||
Error: [[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]</pre> |
Error: [[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]</pre> |
||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">use Math::BigRat try=>"GMP"; |
||
sub taneval { |
sub taneval { |
||
Line 1,584: | Line 2,006: | ||
test([44,'1/57'],[7,'1/239'],[-12,'1/682'],[24,'1/12943']); |
test([44,'1/57'],[7,'1/239'],[-12,'1/682'],[24,'1/12943']); |
||
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12943']); |
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12943']); |
||
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12944']);</ |
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12944']);</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> OK ([1 1/2] [1 1/3]) |
<pre> OK ([1 1/2] [1 1/3]) |
||
Line 1,603: | Line 2,025: | ||
OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) |
OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) |
||
Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12944])</pre> |
Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12944])</pre> |
||
=={{header|Phix}}== |
|||
===Naive version=== |
|||
Rather than test tan(a) for 1.0, test whether the sprint of it, which is rounded to 10 significant digits, is "1.0" or "1".<br> |
|||
At the end we deliberately show a test case that should and does fail. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
=={{header|Perl 6}}== |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
{{Works with|rakudo|2018.03}} |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> |
|||
The coercion to FatRat provides for exact computation for all input. |
|||
<span style="color: #008080;">if</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">3</span><span style="color: #0000FF;">*</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">a</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span> <span style="color: #0000FF;"><=</span> <span style="color: #000000;">a</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
{{trans|Perl}} |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">))</span> |
|||
<lang perl6>sub taneval ($coef, $f) { |
|||
<span style="color: #0000FF;">?</span><span style="color: #000000;">s</span> <span style="color: #000080;font-style:italic;">-- or test for "1.0"/"1", but not 1.0</span> |
|||
return 0 if $coef == 0; |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
return $f if $coef == 1; |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">))</span> |
|||
return -taneval(-$coef, $f) if $coef < 0; |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">))</span> |
|||
my $a = taneval($coef+>1, $f); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">79</span><span style="color: #0000FF;">))</span> |
|||
my $b = taneval($coef - $coef+>1, $f); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">29</span><span style="color: #0000FF;">/</span> <span style="color: #000000;">278</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">79</span><span style="color: #0000FF;">))</span> |
|||
($a+$b)/(1-$a*$b); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">))</span> |
|||
} |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">99</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">53</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">4443</span><span style="color: #0000FF;">))</span> |
|||
sub tans (@xs) { |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">57</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">))</span> |
|||
return taneval(@xs[0;0], @xs[0;1].FatRat) if @xs == 1; |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">515</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">12</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">57</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">))</span> |
|||
my $a = tans(@xs[0 .. (-1+@xs+>1)]); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">16</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">21</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">1042</span><span style="color: #0000FF;">))</span> |
|||
my $b = tans(@xs[(-1+@xs+>1)+1 .. -1+@xs]); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">22</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">28</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">443</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">1393</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">11018</span><span style="color: #0000FF;">))</span> |
|||
($a+$b)/(1-$a*$b); |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">22</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">38</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">17</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">7</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">601</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">7</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">8149</span><span style="color: #0000FF;">))</span> |
|||
} |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">44</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">57</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">12</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">682</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">24</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">12943</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">88</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">172</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">51</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">32</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">682</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">44</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">5357</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">68</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">12943</span><span style="color: #0000FF;">))</span> |
|||
sub verify (@eqn) { |
|||
<span style="color: #0000FF;">?</span><span style="color: #008000;">"==="</span> |
|||
printf "%5s (%s)\n", (tans(@eqn) == 1) ?? "OK" !! "Error", |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">88</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">172</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">51</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">239</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">32</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">682</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">44</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">5357</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">68</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">12944</span><span style="color: #0000FF;">))</span> |
|||
(map { "[{.[0]} {.[1].nude.join('/')}]" }, @eqn).join(' '); |
|||
<!--</syntaxhighlight>--> |
|||
} |
|||
verify($_) for |
|||
([[1,1/2], [1,1/3]], |
|||
[[2,1/3], [1,1/7]], |
|||
[[4,1/5], [-1,1/239]], |
|||
[[5,1/7], [2,3/79]], |
|||
[[5,29/278], [7,3/79]], |
|||
[[1,1/2], [1,1/5], [1,1/8]], |
|||
[[4,1/5], [-1,1/70], [1,1/99]], |
|||
[[5,1/7], [4,1/53], [2,1/4443]], |
|||
[[6,1/8], [2,1/57], [1,1/239]], |
|||
[[8,1/10], [-1,1/239], [-4,1/515]], |
|||
[[12,1/18], [8,1/57], [-5,1/239]], |
|||
[[16,1/21], [3,1/239], [4,3/1042]], |
|||
[[22,1/28], [2,1/443], [-5,1/1393], [-10,1/11018]], |
|||
[[22,1/38], [17,7/601], [10,7/8149]], |
|||
[[44,1/57], [7,1/239], [-12,1/682], [24,1/12943]], |
|||
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/12943]], |
|||
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/21944]] |
|||
);</lang> |
|||
{{out}} |
|||
<pre> OK ([1 1/2] [1 1/3]) |
|||
OK ([2 1/3] [1 1/7]) |
|||
OK ([4 1/5] [-1 1/239]) |
|||
OK ([5 1/7] [2 3/79]) |
|||
OK ([5 29/278] [7 3/79]) |
|||
OK ([1 1/2] [1 1/5] [1 1/8]) |
|||
OK ([4 1/5] [-1 1/70] [1 1/99]) |
|||
OK ([5 1/7] [4 1/53] [2 1/4443]) |
|||
OK ([6 1/8] [2 1/57] [1 1/239]) |
|||
OK ([8 1/10] [-1 1/239] [-4 1/515]) |
|||
OK ([12 1/18] [8 1/57] [-5 1/239]) |
|||
OK ([16 1/21] [3 1/239] [4 3/1042]) |
|||
OK ([22 1/28] [2 1/443] [-5 1/1393] [-10 1/11018]) |
|||
OK ([22 1/38] [17 7/601] [10 7/8149]) |
|||
OK ([44 1/57] [7 1/239] [-12 1/682] [24 1/12943]) |
|||
OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) |
|||
Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/21944])</pre> |
|||
=={{header|Phix}}== |
|||
===Naieve version=== |
|||
Hint: rather than test tan(a) for 1.0, test whether the sprint of it, which is rounded to 10 significant digits, is "1.0".<br> |
|||
The failing test case, I believe, is only accurate to 6 (or perhaps 7, see fractions output) significant digits. |
|||
<lang Phix>procedure test(atom a) |
|||
if -3*PI/4 >= a then ?9/0 end if |
|||
if 5*PI/4 <= a then ?9/0 end if |
|||
string s = sprint(tan(a)) |
|||
?s -- or test for "1.0", but not 1.0 |
|||
end procedure |
|||
test( arctan(1 / 2) + arctan(1 / 3)) |
|||
test( 2*arctan(1 / 3) + arctan(1 / 7)) |
|||
test( 4*arctan(1 / 5) - arctan(1 / 239)) |
|||
test( 5*arctan(1 / 7) + 2*arctan(3 / 79)) |
|||
test( 5*arctan(29/ 278) + 7*arctan(3 / 79)) |
|||
test( arctan(1 / 2) + arctan(1 / 5) + arctan(1 / 8)) |
|||
test( 4*arctan(1 / 5) - arctan(1 / 70) + arctan(1 / 99)) |
|||
test( 5*arctan(1 / 7) + 4*arctan(1 / 53) + 2*arctan(1 / 4443)) |
|||
test( 6*arctan(1 / 8) + 2*arctan(1 / 57) + arctan(1 / 239)) |
|||
test( 8*arctan(1 / 10) - arctan(1 / 239) - 4*arctan(1 / 515)) |
|||
test(12*arctan(1 / 18) + 8*arctan(1 / 57) - 5*arctan(1 / 239)) |
|||
test(16*arctan(1 / 21) + 3*arctan(1 / 239) + 4*arctan(3 / 1042)) |
|||
test(22*arctan(1 / 28) + 2*arctan(1 / 443) - 5*arctan(1 / 1393) - 10*arctan(1 / 11018)) |
|||
test(22*arctan(1 / 38) + 17*arctan(7 / 601) +10*arctan(7 / 8149)) |
|||
test(44*arctan(1 / 57) + 7*arctan(1 / 239) -12*arctan(1 / 682) + 24*arctan(1 / 12943)) |
|||
test(88*arctan(1 / 172) + 51*arctan(1 / 239) +32*arctan(1 / 682) + 44*arctan(1 / 5357) + 68*arctan(1 / 12943)) |
|||
?"===" |
|||
test(88*arctan(1 / 172) + 51*arctan(1 / 239) + 32*arctan(1 / 682) + 44*arctan(1 / 5357) + 68*arctan(1 / 12944))</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,721: | Line 2,080: | ||
===Using proper fractions=== |
===Using proper fractions=== |
||
{{ |
{{libheader|Phix/mpfr}} |
||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
Routines adapted from [[Arithmetic/Rational#Phix]]<br> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<lang Phix>include builtins\pfrac.e -- (provisional/0.8.0+) |
|||
<span style="color: #008080;">include</span> <span style="color: #004080;">mpfr</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
function tans(sequence x) |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">)</span> |
|||
frac a,b |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">args</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">))</span> |
|||
integer h |
|||
<span style="color: #004080;">mpq</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">aab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mab</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpq_inits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span> |
|||
if length(x)=1 then |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">h</span> |
|||
{integer m, frac f} = x[1] |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
if m=1 then |
|||
<span style="color: #0000FF;">{</span><span style="color: #004080;">integer</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">mpq</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
return f |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
elsif m<0 then |
|||
<span style="color: #7060A8;">mpq_set</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> |
|||
return frac_uminus(tans({{-m,f}})) |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span> |
|||
end if |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
h = floor(m/2) |
|||
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">({{-</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">}})</span> |
|||
a = tans({{h,f}}) |
|||
<span style="color: #7060A8;">mpq_neg</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> |
|||
b = tans({{m-h,f}}) |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">f</span> |
|||
else |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
h = floor(length(x)/2) |
|||
<span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
a = tans(x[1..h]) |
|||
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">}})</span> |
|||
b = tans(x[h+1..$]) |
|||
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">m</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">}})</span> |
|||
end if |
|||
<span style="color: #008080;">else</span> |
|||
return frac_div(frac_add(a,b) , frac_sub(frac_new(1),frac_mul(a,b))) |
|||
<span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
end function |
|||
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">h</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">h</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</span> |
|||
function parse(string formula) |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
-- obviously the error handling here is a bit brutal... |
|||
<span style="color: #7060A8;">mpq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> |
|||
sequence res = {}, r |
|||
<span style="color: #7060A8;">mpq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">aab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> |
|||
integer m,n,d |
|||
<span style="color: #7060A8;">mpq_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
formula = substitute(formula," ","") -- strip spaces |
|||
<span style="color: #7060A8;">mpq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mab</span><span style="color: #0000FF;">)</span> |
|||
if formula[1..5]!="pi/4=" then ?9/0 end if |
|||
<span style="color: #7060A8;">mpq_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">aab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> |
|||
formula = formula[6..$] |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">aab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mab</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpq_free</span><span style="color: #0000FF;">({</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">aab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mab</span><span style="color: #0000FF;">})</span> |
|||
res = {} |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span> |
|||
while length(formula) do |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
integer sgn = +1 |
|||
switch formula[1] do |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">parse</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> |
|||
case '-': sgn = -1; fallthrough |
|||
<span style="color: #000080;font-style:italic;">-- obviously the error handling here is a bit brutal...</span> |
|||
case '+': formula = formula[2..$] |
|||
<span style="color: #000000;">formula</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- strip spaces</span> |
|||
end switch |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">5</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">"pi/4="</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
if formula[1]='a' then |
|||
<span style="color: #000000;">formula</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">6</span><span style="color: #0000FF;">..$]</span> |
|||
m = sgn |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000000;">r</span> |
|||
else |
|||
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
r = scanf(formula,"%d*%s") |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">sgn</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span> |
|||
if length(r)!=1 then ?9/0 end if |
|||
<span style="color: #008080;">switch</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span> |
|||
{m,formula} = r[1] |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'-'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sgn</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">;</span> <span style="color: #008080;">fallthrough</span> |
|||
m *= sgn |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'+'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">formula</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span> |
|||
end if |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span> |
|||
r = scanf(formula,"arctan(%d/%d)%s") |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'a'</span> <span style="color: #008080;">then</span> |
|||
if length(r)!=1 then ?9/0 end if |
|||
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sgn</span> |
|||
{n,d,formula} = r[1] |
|||
<span style="color: #008080;">else</span> |
|||
res = append(res,{m,frac_new(n,d)}) |
|||
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d*%s"</span><span style="color: #0000FF;">)</span> |
|||
end while |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
return res |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
end function |
|||
<span style="color: #000000;">m</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">sgn</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
procedure test(string formula) |
|||
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"arctan(%d/%d)%s"</span><span style="color: #0000FF;">)</span> |
|||
frac f = tans(parse(formula)) |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
if frac_eq(f,frac_one) then |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
printf(1,"OK: %s\n",{formula}) |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">mpq_init_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)})</span> |
|||
else |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
printf(1,"ERROR: %s\n",{formula}) |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span> |
|||
printf(1," %s\n\\ %s\n",frac_sprint(f,asPair:=true)) |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
end if |
|||
end procedure |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">mpq</span> <span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tans</span><span style="color: #0000FF;">(</span><span style="color: #000000;">parse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">))</span> |
|||
constant formulae = {"pi/4 = arctan(1/2) + arctan(1/3)", |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">mpq_cmp_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
"pi/4 = 2*arctan(1/3) + arctan(1/7)", |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"OK: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">})</span> |
|||
"pi/4 = 4*arctan(1/5) - arctan(1/239)", |
|||
<span style="color: #008080;">else</span> |
|||
"pi/4 = 5*arctan(1/7) + 2*arctan(3/79)", |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ERROR: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">})</span> |
|||
"pi/4 = 5*arctan(29/278) + 7*arctan(3/79)", |
|||
<span style="color: #004080;">mpz</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_inits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
"pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)", |
|||
<span style="color: #7060A8;">mpq_get_num</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> |
|||
"pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)", |
|||
<span style="color: #7060A8;">mpq_get_den</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> |
|||
"pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)", |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" %s\n\\ %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">shorten</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">mpz_get_str</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)),</span> |
|||
"pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)", |
|||
<span style="color: #7060A8;">shorten</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">mpz_get_str</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">))})</span> |
|||
"pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)", |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
"pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)", |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
"pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)", |
|||
"pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)", |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">formulae</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"pi/4 = arctan(1/2) + arctan(1/3)"</span><span style="color: #0000FF;">,</span> |
|||
"pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)", |
|||
"pi/4 = |
<span style="color: #008000;">"pi/4 = 2*arctan(1/3) + arctan(1/7)"</span><span style="color: #0000FF;">,</span> |
||
"pi/4 = |
<span style="color: #008000;">"pi/4 = 4*arctan(1/5) - arctan(1/239)"</span><span style="color: #0000FF;">,</span> |
||
"pi/4 = |
<span style="color: #008000;">"pi/4 = 5*arctan(1/7) + 2*arctan(3/79)"</span><span style="color: #0000FF;">,</span> |
||
<span style="color: #008000;">"pi/4 = 5*arctan(29/278) + 7*arctan(3/79)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)"</span><span style="color: #0000FF;">,</span> |
|||
for i=1 to length(formulae) do |
|||
<span style="color: #008000;">"pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)"</span><span style="color: #0000FF;">,</span> |
|||
test(formulae[i]) |
|||
<span style="color: #008000;">"pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)"</span><span style="color: #0000FF;">,</span> |
|||
end for</lang> |
|||
<span style="color: #008000;">"pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #008000;">"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)"</span><span style="color: #0000FF;">}</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formulae</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formulae</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
{{out}} |
||
As above, the last case should and does fail. |
|||
Last line manually edited (both numerator and denominator were 550-digit numbers). |
|||
<pre> |
<pre> |
||
OK: |
OK: pi/4 = arctan(1/2) + arctan(1/3) |
||
OK: |
OK: pi/4 = 2*arctan(1/3) + arctan(1/7) |
||
OK: |
OK: pi/4 = 4*arctan(1/5) - arctan(1/239) |
||
OK: |
OK: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) |
||
OK: |
OK: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) |
||
OK: |
OK: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) |
||
OK: |
OK: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) |
||
OK: |
OK: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) |
||
OK: |
OK: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) |
||
OK: |
OK: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) |
||
OK: |
OK: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) |
||
OK: |
OK: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) |
||
OK: |
OK: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) |
||
OK: |
OK: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) |
||
OK: |
OK: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) |
||
OK: |
OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) |
||
ERROR: |
ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) |
||
10092880180009440509...99840402353522108223 (550 digits) |
|||
10092880180009440509678967104315871864562569285843 ... 82862528690942242793667539020699840402353522108223 |
|||
\ 10092888373156385834...60371264507984339711 (550 digits) |
|||
\ 10092888373156385834157015287804027957219356416144 ... 84010722587072087349909684004660371264507984339711 |
|||
</pre> |
</pre> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
This example parses the [http://rosettacode.org/mw/index.php?title=Check_Machin-like_formulas&oldid=146749 original] equations to form an intermediate representation then does the checks.<br> |
This example parses the [http://rosettacode.org/mw/index.php?title=Check_Machin-like_formulas&oldid=146749 original] equations to form an intermediate representation then does the checks.<br> |
||
Function tans and tanEval are translations of the |
Function tans and tanEval are translations of the Haskell functions of the same names. |
||
< |
<syntaxhighlight lang="python">import re |
||
from fractions import Fraction |
from fractions import Fraction |
||
from pprint import pprint as pp |
from pprint import pprint as pp |
||
Line 1,904: | Line 2,276: | ||
for machin, eqn in zip(machins, equationtext.split('\n')): |
for machin, eqn in zip(machins, equationtext.split('\n')): |
||
ans = tans(machin) |
ans = tans(machin) |
||
print('%5s: %s' % ( ('OK' if ans == 1 else 'ERROR'), eqn))</ |
print('%5s: %s' % ( ('OK' if ans == 1 else 'ERROR'), eqn))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,926: | Line 2,298: | ||
'''Note:''' the [http://kodos.sourceforge.net/ Kodos] tool was used in developing the regular expression. |
'''Note:''' the [http://kodos.sourceforge.net/ Kodos] tool was used in developing the regular expression. |
||
=={{header|R}}== |
=={{header|R}}== |
||
< |
<syntaxhighlight lang="rsplus"> |
||
#lang R |
#lang R |
||
library(Rmpfr) |
library(Rmpfr) |
||
Line 1,935: | Line 2,306: | ||
# function for checking identity of tan of expression and 1, making use of high precision division operator %:% |
# function for checking identity of tan of expression and 1, making use of high precision division operator %:% |
||
tanident_1 <- function(x) identical(round(tan(eval(parse(text = gsub("/", "%:%", deparse(substitute(x)))))), (prec/10)), mpfr(1, prec)) |
tanident_1 <- function(x) identical(round(tan(eval(parse(text = gsub("/", "%:%", deparse(substitute(x)))))), (prec/10)), mpfr(1, prec)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<syntaxhighlight lang="r"> |
|||
<lang R> |
|||
tanident_1( 1*atan(1/2) + 1*atan(1/3) ) |
tanident_1( 1*atan(1/2) + 1*atan(1/3) ) |
||
## [1] TRUE |
## [1] TRUE |
||
Line 1,973: | Line 2,344: | ||
tanident_1(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944)) |
tanident_1(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944)) |
||
## [1] FALSE |
## [1] FALSE |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(define (reduce e) |
(define (reduce e) |
||
Line 2,033: | Line 2,403: | ||
(displayln "The incorrect formula reduces to:") |
(displayln "The incorrect formula reduces to:") |
||
(reduce wrong-formula) |
(reduce wrong-formula) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
< |
<syntaxhighlight lang="racket"> |
||
Do all correct formulas reduce to 1? |
Do all correct formulas reduce to 1? |
||
#t |
#t |
||
The incorrect formula reduces to: |
The incorrect formula reduces to: |
||
1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223/1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711 |
1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223/1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{Works with|rakudo|2018.03}} |
|||
The coercion to FatRat provides for exact computation for all input. |
|||
{{trans|Perl}} |
|||
<syntaxhighlight lang="raku" line>sub taneval ($coef, $f) { |
|||
return 0 if $coef == 0; |
|||
return $f if $coef == 1; |
|||
return -taneval(-$coef, $f) if $coef < 0; |
|||
my $a = taneval($coef+>1, $f); |
|||
my $b = taneval($coef - $coef+>1, $f); |
|||
($a+$b)/(1-$a*$b); |
|||
} |
|||
sub tans (@xs) { |
|||
return taneval(@xs[0;0], @xs[0;1].FatRat) if @xs == 1; |
|||
my $a = tans(@xs[0 .. (-1+@xs+>1)]); |
|||
my $b = tans(@xs[(-1+@xs+>1)+1 .. -1+@xs]); |
|||
($a+$b)/(1-$a*$b); |
|||
} |
|||
sub verify (@eqn) { |
|||
printf "%5s (%s)\n", (tans(@eqn) == 1) ?? "OK" !! "Error", |
|||
(map { "[{.[0]} {.[1].nude.join('/')}]" }, @eqn).join(' '); |
|||
} |
|||
verify($_) for |
|||
([[1,1/2], [1,1/3]], |
|||
[[2,1/3], [1,1/7]], |
|||
[[4,1/5], [-1,1/239]], |
|||
[[5,1/7], [2,3/79]], |
|||
[[5,29/278], [7,3/79]], |
|||
[[1,1/2], [1,1/5], [1,1/8]], |
|||
[[4,1/5], [-1,1/70], [1,1/99]], |
|||
[[5,1/7], [4,1/53], [2,1/4443]], |
|||
[[6,1/8], [2,1/57], [1,1/239]], |
|||
[[8,1/10], [-1,1/239], [-4,1/515]], |
|||
[[12,1/18], [8,1/57], [-5,1/239]], |
|||
[[16,1/21], [3,1/239], [4,3/1042]], |
|||
[[22,1/28], [2,1/443], [-5,1/1393], [-10,1/11018]], |
|||
[[22,1/38], [17,7/601], [10,7/8149]], |
|||
[[44,1/57], [7,1/239], [-12,1/682], [24,1/12943]], |
|||
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/12943]], |
|||
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/21944]] |
|||
);</syntaxhighlight> |
|||
{{out}} |
|||
<pre> OK ([1 1/2] [1 1/3]) |
|||
OK ([2 1/3] [1 1/7]) |
|||
OK ([4 1/5] [-1 1/239]) |
|||
OK ([5 1/7] [2 3/79]) |
|||
OK ([5 29/278] [7 3/79]) |
|||
OK ([1 1/2] [1 1/5] [1 1/8]) |
|||
OK ([4 1/5] [-1 1/70] [1 1/99]) |
|||
OK ([5 1/7] [4 1/53] [2 1/4443]) |
|||
OK ([6 1/8] [2 1/57] [1 1/239]) |
|||
OK ([8 1/10] [-1 1/239] [-4 1/515]) |
|||
OK ([12 1/18] [8 1/57] [-5 1/239]) |
|||
OK ([16 1/21] [3 1/239] [4 3/1042]) |
|||
OK ([22 1/28] [2 1/443] [-5 1/1393] [-10 1/11018]) |
|||
OK ([22 1/38] [17 7/601] [10 7/8149]) |
|||
OK ([44 1/57] [7 1/239] [-12 1/682] [24 1/12943]) |
|||
OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) |
|||
Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/21944])</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Note: REXX doesn't have many high─order math functions, so a few of them are included here. |
Note: REXX doesn't have many high─order math functions, so a few of them are included here. |
||
Line 2,048: | Line 2,483: | ||
An extra formula was added to stress test the near exactness of a value. |
An extra formula was added to stress test the near exactness of a value. |
||
< |
<syntaxhighlight lang="rexx">/*REXX program evaluates some Machin─like formulas and verifies their veracity. */ |
||
@.=; pi= pi(); numeric digits( length(pi) ) - length(.); numeric fuzz 3 |
@.=; pi= pi(); numeric digits( length(pi) ) - length(.); numeric fuzz 3 |
||
say center(' computing with ' digits() " decimal digits ", 110, '═') |
say center(' computing with ' digits() " decimal digits ", 110, '═') |
||
Line 2,087: | Line 2,522: | ||
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2 |
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2 |
||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/ |
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/ |
||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g</ |
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g</syntaxhighlight> |
||
{{out|output|text= when using the internal default input:}} |
{{out|output|text= when using the internal default input:}} |
||
<pre> |
<pre> |
||
Line 2,109: | Line 2,544: | ||
bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12944) |
bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12944) |
||
bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 67.9999999994*atan(1/12943) |
bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 67.9999999994*atan(1/12943) |
||
</pre> |
|||
=={{header|RPL}}== |
|||
RPL does not support fat integers, therefore fat fractions neither, but the precision of floating-point numbers is actually sufficient to detect the incorrect formula and validate the other ones without using any trigonometric function. The 17 formulas to be checked are stored as strings in a global variable; each string is converted into a list of coefficients and real numbers, on which <code>tan(a+b)=(tan(a)+tan(b))/(1-tan(a)*tan(b))</code> is recursively applied, in a similar way to other languages. |
|||
{ "1*arctan(1/2) + 1*arctan(1/3)" |
|||
"2*arctan(1/3) + 1*arctan(1/7)" |
|||
"4*arctan(1/5) + -1*arctan(1/239)" |
|||
"5*arctan(1/7) + 2*arctan(3/79)" |
|||
"5*arctan(29/278) + 7*arctan(3/79)" |
|||
"1*arctan(1/2) + 1*arctan(1/5) + 1*arctan(1/8)" |
|||
"4*arctan(1/5) + -1*arctan(1/70) + 1*arctan(1/99)" |
|||
"5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)" |
|||
"6*arctan(1/8) + 2*arctan(1/57) + 1*arctan(1/239)" |
|||
"8*arctan(1/10) + -1*arctan(1/239) + -4*arctan(1/515)" |
|||
"12*arctan(1/18) + 8*arctan(1/57) + -5*arctan(1/239)" |
|||
"16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)" |
|||
"22*arctan(1/28) + 2*arctan(1/443) + -5*arctan(1/1393) + -10*arctan(1/11018)" |
|||
"22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)" |
|||
"44*arctan(1/57) + 7*arctan(1/239) + -12*arctan(1/682) + 24*arctan(1/12943)" |
|||
"88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)" |
|||
"88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)" |
|||
} ''''Formulas'''' STO |
|||
{{works with|Halcyon Calc|4.2.7}} |
|||
{| class="wikitable" |
|||
! RPL code |
|||
! Comment |
|||
|- |
|||
| |
|||
≪ |
|||
IF DUP 1 == THEN DROP |
|||
ELSE IF DUP 0 < THEN NEG '''TanEval''' NEG |
|||
ELSE DUP2 2 / IP '''TanEval''' ROT ROT |
|||
DUP 2 / IP - '''TanEval''' |
|||
+ LAST * 1 - NEG / |
|||
END END |
|||
≫ ‘'''TanEval'''’ STO |
|||
≪ |
|||
DUP 2 GET →NUM OVER 1 GET →NUM '''TanEval''' SWAP |
|||
IF DUP SIZE 3 ≥ THEN |
|||
LIST→ 2 - →LIST ROT ROT DROP2 |
|||
'''TanSum''' SWAP + LAST * 1 - NEG / |
|||
ELSE DROP END |
|||
≫ ‘'''TanSum'''’ STO |
|||
≪ DUP "+" POS → eq op |
|||
≪ IF op THEN eq op 1 + OVER SIZE SUB eq 1 op 1 - SUB |
|||
ELSE "" eq END |
|||
"'" DUP ROT SWAP + + STR→ |
|||
≫ ≫ ''''PopTerm'''' STO |
|||
≪ |
|||
{} SWAP WHILE DUP "" ≠ REPEAT |
|||
'''PopTerm''' |
|||
ROT OVER 1 EXGET + SWAP DUP SIZE 1 - EXGET + SWAP |
|||
END DROP |
|||
≫ ‘'''ParsExp'''’ STO |
|||
≪ 1 CF 0 |
|||
1 '''Formulas''' SIZE FOR f |
|||
'''Formulas''' f GET '''ParsExp TanSum''' |
|||
IF RND 1 == THEN 1 + |
|||
ELSE |
|||
1 SF "INCORRECT: π/4 ≠ " |
|||
'''Formulas''' f GET + SWAP |
|||
END NEXT |
|||
→STR IF 1 FS? THEN " others" + END " OK" + |
|||
≫ ‘'''TASK'''’ STO |
|||
| |
|||
'''TanEval''' ''( f c -- tan(c*arctan(f)) )'' |
|||
if c = 1 then return f |
|||
else if c < 0 then return -tan(-c*arctan(f)) |
|||
else put a = tan((c%2)*arctan(f)) at stack level 3 |
|||
get b = tan((c-c%2)*arctan(f)) |
|||
return (a+b)/(-(a*b-1)) |
|||
'''TanSum''' ''( { c1 f1 .. cn fn } -- result )'' |
|||
Get tan(c1*arctan(f1)) |
|||
if input list > 2 items |
|||
make { c2 f2 .. cn fn } |
|||
evaluate tan of { c2..fn } and add it to |
|||
otherwise drop empty list |
|||
'''PopTerm''' ''( "T1+T2+..+Tn" -- "T2+..+Tn" 'T1' )'' |
|||
If input string contains "+" then split it |
|||
else string contains only the last term |
|||
convert term into algebraic expression |
|||
'''ParsExp''' ''( "Machin formula" -- { c1 f1 .. cn fn } )'' |
|||
Scan the formula |
|||
extract next term |
|||
extract c and f |
|||
Drop empty string |
|||
Initialize flag and counter |
|||
Scan list of formulas |
|||
evaluate tan(formula) |
|||
if ok, increase counter |
|||
else |
|||
build error message |
|||
with incorrect formula |
|||
Finalize report |
|||
|} |
|||
{{out}} |
|||
<pre> |
|||
2: "INCORRECT: π/4 ≠ 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)" |
|||
1: "16 others OK" |
|||
</pre> |
</pre> |
||
=={{header|Seed7}}== |
=={{header|Seed7}}== |
||
< |
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
||
include "bigint.s7i"; |
include "bigint.s7i"; |
||
include "bigrat.s7i"; |
include "bigrat.s7i"; |
||
Line 2,183: | Line 2,731: | ||
writeln; |
writeln; |
||
end for; |
end for; |
||
end func;</ |
end func;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,207: | Line 2,755: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="ruby">var equationtext = <<'EOT' |
||
pi/4 = arctan(1/2) + arctan(1/3) |
pi/4 = arctan(1/2) + arctan(1/3) |
||
pi/4 = 2*arctan(1/3) + arctan(1/7) |
pi/4 = 2*arctan(1/3) + arctan(1/7) |
||
Line 2,268: | Line 2,816: | ||
var ans = tans(machin) |
var ans = tans(machin) |
||
printf("%5s: %s\n", (ans == 1 ? 'OK' : 'ERROR'), eqn) |
printf("%5s: %s\n", (ans == 1 ? 'OK' : 'ERROR'), eqn) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,289: | Line 2,837: | ||
ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) |
ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) |
||
</pre> |
</pre> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.5 |
||
# Compute tan(atan(p)+atan(q)) using rationals |
# Compute tan(atan(p)+atan(q)) using rationals |
||
Line 2,369: | Line 2,916: | ||
puts "No! '$formula' not true" |
puts "No! '$formula' not true" |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,390: | Line 2,937: | ||
No! 'pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)' not true |
No! 'pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)' not true |
||
</pre> |
</pre> |
||
=={{header|Wren}}== |
|||
{{trans|Kotlin}} |
|||
{{libheader|Wren-big}} |
|||
{{libheader|Wren-fmt}} |
|||
We already have a BigRat class so we use that. |
|||
<syntaxhighlight lang="wren">import "./big" for BigRat |
|||
import "./fmt" for Fmt |
|||
/** represents a term of the form: c * atan(n / d) */ |
|||
=={{header|Visual Basic .NET}}== |
|||
class Term { |
|||
'''BigRat''' class based on the Arithmetic/Rational#C here at Rosetta Code.<br/> |
|||
construct new(c, n, d) { |
|||
The parser here allows for some flexibility in the input text. Case is ignored, and a variable number of spaces are allowed. Atan(), arctan(), atn() are all recognized as valid. If one of those three are not found, a warning will appear. The coefficient need not have a multiplication sign between it and the "arctan()". The left side of the equation must be pi / 4, otherwise a warning will appear. |
|||
_c = c |
|||
<lang vbnet>Imports System.Numerics |
|||
_n = n |
|||
_d = d |
|||
} |
|||
c { _c } |
|||
Public Class BigRat ' Big Rational Class constructed with BigIntegers |
|||
n { _n } |
|||
Implements IComparable |
|||
d { _d } |
|||
Public Shared Zero = New BigRat(BigInteger.Zero, BigInteger.One), |
|||
One = New BigRat(BigInteger.One, BigInteger.One) |
|||
Sub New(bRat As BigRat) |
|||
nu = bRat.nu : de = bRat.de |
|||
End Sub |
|||
Sub New(n As BigInteger, d As BigInteger) |
|||
If d = BigInteger.Zero Then _ |
|||
Throw (New Exception(String.Format("tried to set a BigRat with ({0}/{1})", n, d))) |
|||
Dim bi As BigInteger = BigInteger.GreatestCommonDivisor(n, d) |
|||
If bi > BigInteger.One Then n /= bi : d /= bi |
|||
If d < BigInteger.Zero Then n = -n : d = -d |
|||
nu = n : de = d |
|||
End Sub |
|||
Shared Operator -(x As BigRat) As BigRat |
|||
Return New BigRat(-x.nu, x.de) |
|||
End Operator |
|||
Shared Operator +(x As BigRat, y As BigRat) |
|||
Return New BigRat(x.nu * y.de + x.de * y.nu, x.de * y.de) |
|||
End Operator |
|||
Shared Operator -(x As BigRat, y As BigRat) As BigRat |
|||
Return x + (-y) |
|||
End Operator |
|||
Shared Operator *(x As BigRat, y As BigRat) As BigRat |
|||
Return New BigRat(x.nu * y.nu, x.de * y.de) |
|||
End Operator |
|||
Shared Operator /(x As BigRat, y As BigRat) As BigRat |
|||
Return New BigRat(x.nu * y.de, x.de * y.nu) |
|||
End Operator |
|||
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo |
|||
Dim dif As BigRat = New BigRat(nu, de) - obj |
|||
If dif.nu < BigInteger.Zero Then Return -1 |
|||
If dif.nu > BigInteger.Zero Then Return 1 |
|||
Return 0 |
|||
End Function |
|||
Shared Operator =(x As BigRat, y As BigRat) As Boolean |
|||
Return x.CompareTo(y) = 0 |
|||
End Operator |
|||
Shared Operator <>(x As BigRat, y As BigRat) As Boolean |
|||
Return x.CompareTo(y) <> 0 |
|||
End Operator |
|||
Overrides Function ToString() As String |
|||
If de = BigInteger.One Then Return nu.ToString |
|||
Return String.Format("({0}/{1})", nu, de) |
|||
End Function |
|||
Shared Function Combine(a As BigRat, b As BigRat) As BigRat |
|||
Return (a + b) / (BigRat.One - (a * b)) |
|||
End Function |
|||
End Class |
|||
toString { |
|||
Public Structure Term ' coefficent, BigRational construction for each term |
|||
var a = "atan(%(n)/%(d))" |
|||
return ((_c == 1) ? " + " : |
|||
Sub New(cc As Integer, bigr As BigRat) |
|||
(_c == -1) ? " - " : |
|||
(_c < 0) ? " - %(-c)*" : " + %(c)*") + a |
|||
End Sub |
|||
} |
|||
End Structure |
|||
} |
|||
var tanEval // recursive function |
|||
Module Module1 |
|||
tanEval = Fn.new { |c, f| |
|||
Function Eval(c As Integer, x As BigRat) As BigRat |
|||
if (c == 1) return f |
|||
If c = 1 Then Return x Else If c < 0 Then Return Eval(-c, -x) |
|||
if (c < 0) return -tanEval.call(-c, f) |
|||
Dim hc As Integer = c \ 2 |
|||
var ca = (c/2).truncate |
|||
Return BigRat.Combine(Eval(hc, x), Eval(c - hc, x)) |
|||
var cb = c - ca |
|||
var a = tanEval.call(ca, f) |
|||
var b = tanEval.call(cb, f) |
|||
return (a + b) / (BigRat.one - (a * b)) |
|||
} |
|||
var tanSum // recursive function |
|||
Function Sum(terms As List(Of Term)) As BigRat |
|||
tanSum = Fn.new { |terms| |
|||
If terms.Count = 1 Then Return Eval(terms(0).c, terms(0).br) |
|||
if (terms.count == 1) return tanEval.call(terms[0].c, BigRat.new(terms[0].n, terms[0].d)) |
|||
Dim htc As Integer = terms.Count / 2 |
|||
var half = (terms.count/2).floor |
|||
Return BigRat.Combine(Sum(terms.Take(htc).ToList), Sum(terms.Skip(htc).ToList)) |
|||
var a = tanSum.call(terms.take(half).toList) |
|||
End Function |
|||
var b = tanSum.call(terms.skip(half).toList) |
|||
return (a + b) / (BigRat.one - (a * b)) |
|||
} |
|||
var T = Term // type alias |
|||
Function ParseLine(ByVal s As String) As List(Of Term) |
|||
ParseLine = New List(Of Term) : Dim t As String = s.ToLower, p As Integer, x As New Term(1, BigRat.Zero) |
|||
var termsList = [ |
|||
While t.Contains(" ") : t = t.Replace(" ", "") : End While |
|||
[T.new(1, 1, 2), T.new(1, 1, 3)], |
|||
p = t.IndexOf("pi/4=") : If p < 0 Then _ |
|||
[T.new(2, 1, 3), T.new(1, 1, 7)], |
|||
Console.WriteLine("warning: tan(left side of equation) <> 1") : ParseLine.Add(x) : Exit Function |
|||
[T.new(4, 1, 5), T.new(-1, 1, 239)], |
|||
[T.new(5, 1, 7), T.new(2, 3, 79)], |
|||
For Each item As String In t.Split(")") |
|||
[T.new(5, 29, 278), T.new(7, 3, 79)], |
|||
If item.Length > 5 Then |
|||
[T.new(1, 1, 2), T.new(1, 1, 5), T.new(1, 1, 8)], |
|||
If (Not item.Contains("tan") OrElse item.IndexOf("a") < 0 OrElse |
|||
[T.new(4, 1, 5), T.new(-1, 1, 70), T.new(1, 1, 99)], |
|||
item.IndexOf("a") > item.IndexOf("tan")) AndAlso Not item.Contains("atn") Then |
|||
[T.new(5, 1, 7), T.new(4, 1, 53), T.new(2, 1, 4443)], |
|||
Console.WriteLine("warning: a term is mising a valid arctangent identifier on the right side of the equation: [{0})]", item) |
|||
[T.new(6, 1, 8), T.new(2, 1, 57), T.new(1, 1, 239)], |
|||
ParseLine = New List(Of Term) : ParseLine.Add(New Term(1, BigRat.Zero)) : Exit Function |
|||
[T.new(8, 1, 10), T.new(-1, 1, 239), T.new(-4, 1, 515)], |
|||
End If |
|||
[T.new(12, 1, 18), T.new(8, 1, 57), T.new(-5, 1, 239)], |
|||
x.c = 1 : x.br = New BigRat(BigRat.One) |
|||
[T.new(16, 1, 21), T.new(3, 1, 239), T.new(4, 3, 1042)], |
|||
p = item.IndexOf("/") : If p > 0 Then |
|||
[T.new(22, 1, 28), T.new(2, 1, 443), T.new(-5, 1, 1393), T.new(-10, 1, 11018)], |
|||
x.br.de = UInt64.Parse(item.Substring(p + 1)) |
|||
[T.new(22, 1, 38), T.new(17, 7, 601), T.new(10, 7, 8149)], |
|||
item = item.Substring(0, p) |
|||
[T.new(44, 1, 57), T.new(7, 1, 239), T.new(-12, 1, 682), T.new(24, 1, 12943)], |
|||
p = item.IndexOf("(") : If p > 0 Then |
|||
[T.new(88, 1, 172), T.new(51, 1, 239), T.new(32, 1, 682), T.new(44, 1, 5357), T.new(68, 1, 12943)], |
|||
x.br.nu = UInt64.Parse(item.Substring(p + 1)) |
|||
[T.new(88, 1, 172), T.new(51, 1, 239), T.new(32, 1, 682), T.new(44, 1, 5357), T.new(68, 1, 12944)] |
|||
p = item.IndexOf("a") : If p > 0 Then |
|||
] |
|||
Integer.TryParse(item.Substring(0, p).Replace("*", ""), x.c) |
|||
If x.c = 0 Then x.c = 1 |
|||
for (terms in termsList) { |
|||
If item.Contains("-") AndAlso x.c > 0 Then x.c = -x.c |
|||
var f = Fmt.swrite("$-5s: 1 == tan(", tanSum.call(terms) == BigRat.one) |
|||
End If |
|||
System.write(f) |
|||
ParseLine.Add(x) |
|||
System.write(terms[0].toString.skip(3).join()) |
|||
End If |
|||
for (i in 1...terms.count) System.write(terms[i]) |
|||
End If |
|||
System.print(")") |
|||
End If |
|||
}</syntaxhighlight> |
|||
Next |
|||
End Function |
|||
Sub Main(ByVal args As String()) |
|||
Dim nl As String = vbLf |
|||
For Each item In ("pi/4 = ATan(1 / 2) + ATan(1/3)" & nl & |
|||
"pi/4 = 2Atan(1/3) + ATan(1/7)" & nl & |
|||
"pi/4 = 4ArcTan(1/5) - ATan(1 / 239)" & nl & |
|||
"pi/4 = 5arctan(1/7) + 2 * atan(3/79)" & nl & |
|||
"Pi/4 = 5ATan(29/278) + 7*ATan(3/79)" & nl & |
|||
"pi/4 = atn(1/2) + ATan(1/5) + ATan(1/8)" & nl & |
|||
"PI/4 = 4ATan(1/5) - Atan(1/70) + ATan(1/99)" & nl & |
|||
"pi /4 = 5*ATan(1/7) + 4 ATan(1/53) + 2ATan(1/4443)" & nl & |
|||
"pi / 4 = 6ATan(1/8) + 2arctangent(1/57) + ATan(1/239)" & nl & |
|||
"pi/ 4 = 8ATan(1/10) - ATan(1/239) - 4ATan(1/515)" & nl & |
|||
"pi/4 = 12ATan(1/18) + 8ATan(1/57) - 5ATan(1/239)" & nl & |
|||
"pi/4 = 16 * ATan(1/21) + 3ATan(1/239) + 4ATan(3/1042)" & nl & |
|||
"pi/4 = 22ATan(1/28) + 2ATan(1/443) - 5ATan(1/1393) - 10 ATan( 1 / 11018 )" & nl & |
|||
"pi/4 = 22ATan(1/38) + 17ATan(7/601) + 10ATan(7 / 8149)" & nl & |
|||
"pi/4 = 44ATan(1/57) + 7ATan(1/239) - 12ATan(1/682) + 24ATan(1/12943)" & nl & |
|||
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12943)" & nl & |
|||
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12944)").Split(nl) |
|||
Console.WriteLine("{0}: {1}", If(Sum(ParseLine(item)) = BigRat.One, "Pass", "Fail"), item) |
|||
Next |
|||
End Sub |
|||
End Module</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
|||
<pre>Pass: pi/4 = ATan(1 / 2) + ATan(1/3) |
|||
true : 1 == tan(atan(1/2) + atan(1/3)) |
|||
true : 1 == tan(2*atan(1/3) + atan(1/7)) |
|||
true : 1 == tan(4*atan(1/5) - atan(1/239)) |
|||
true : 1 == tan(5*atan(1/7) + 2*atan(3/79)) |
|||
true : 1 == tan(5*atan(29/278) + 7*atan(3/79)) |
|||
true : 1 == tan(atan(1/2) + atan(1/5) + atan(1/8)) |
|||
true : 1 == tan(4*atan(1/5) - atan(1/70) + atan(1/99)) |
|||
true : 1 == tan(5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443)) |
|||
true : 1 == tan(6*atan(1/8) + 2*atan(1/57) + atan(1/239)) |
|||
true : 1 == tan(8*atan(1/10) - atan(1/239) - 4*atan(1/515)) |
|||
true : 1 == tan(12*atan(1/18) + 8*atan(1/57) - 5*atan(1/239)) |
|||
true : 1 == tan(16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042)) |
|||
true : 1 == tan(22*atan(1/28) + 2*atan(1/443) - 5*atan(1/1393) - 10*atan(1/11018)) |
|||
true : 1 == tan(22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149)) |
|||
true : 1 == tan(44*atan(1/57) + 7*atan(1/239) - 12*atan(1/682) + 24*atan(1/12943)) |
|||
true : 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12943)) |
|||
false: 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944)) |
|||
</pre> |
|||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">code ChOut=8, Text=12; \intrinsic routines |
||
int Number(18); \numbers from equations |
int Number(18); \numbers from equations |
||
def LF=$0A; \ASCII line feed (end-of-line character) |
def LF=$0A; \ASCII line feed (end-of-line character) |
||
Line 2,637: | Line 3,132: | ||
repeat ChOut(0, SS(0)); SS:= SS+1 until SS(0)=LF; ChOut(0, LF); \show equation |
repeat ChOut(0, SS(0)); SS:= SS+1 until SS(0)=LF; ChOut(0, LF); \show equation |
||
]; |
]; |
||
]</ |
]</syntaxhighlight> |
||
{{out}} |
{{out}} |
Latest revision as of 10:58, 17 November 2023
You are encouraged to solve this task according to the task description, using any language you may know.
Machin-like formulas are useful for efficiently computing numerical approximations for
- Task
Verify the following Machin-like formulas are correct by calculating the value of tan (right hand side) for each equation using exact arithmetic and showing they equal 1:
and confirm that the following formula is incorrect by showing tan (right hand side) is not 1:
These identities are useful in calculating the values:
You can store the equations in any convenient data structure, but for extra credit parse them from human-readable text input.
Note: to formally prove the formula correct, it would have to be shown that < right hand side < due to periodicity.
BASIC
FreeBASIC
' version 07-04-2018
' compile with: fbc -s console
#Include "gmp.bi"
#Define _a(Q) (@(Q)->_mp_num) 'a
#Define _b(Q) (@(Q)->_mp_den) 'b
Data "[1, 1, 2] [1, 1, 3]"
Data "[2, 1, 3] [1, 1, 7]"
Data "[4, 1, 5] [-1, 1, 239]"
Data "[5, 1, 7] [2, 3, 79]"
Data "[1, 1, 2] [1, 1, 5] [1, 1, 8]"
Data "[4, 1, 5] [-1, 1, 70] [1, 1, 99]"
Data "[5, 1, 7] [4, 1, 53] [2, 1, 4443]"
Data "[6, 1, 8] [2, 1, 57] [1, 1, 239]"
Data "[8, 1, 10] [-1, 1, 239] [-4, 1, 515]"
Data "[12, 1, 18] [8, 1, 57] [-5, 1, 239]"
Data "[16, 1, 21] [3, 1, 239] [4, 3, 1042]"
Data "[22, 1, 28] [2, 1, 443] [-5, 1, 1393] [-10, 1, 11018]"
Data "[22, 1, 38] [17, 7, 601] [10, 7, 8149]"
Data "[44, 1, 57] [7, 1, 239] [-12, 1, 682] [24, 1, 12943]"
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12943]"
Data "[88, 1, 172] [51, 1, 239] [32, 1, 682] [44, 1, 5357] [68, 1, 12944]"
Data ""
Sub work2do (ByRef a As LongInt, f1 As mpq_ptr)
Dim As LongInt flag = -1
Dim As Mpq_ptr x, y, z
x = Allocate(Len(__mpq_struct)) : Mpq_init(x)
y = Allocate(Len(__mpq_struct)) : Mpq_init(y)
z = Allocate(Len(__mpq_struct)) : Mpq_init(z)
Dim As Mpz_ptr temp1, temp2
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1)
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2)
mpq_set(y, f1)
While a > 0
If (a And 1) = 1 Then
If flag = -1 Then
mpq_set(x, y)
flag = 0
Else
Mpz_mul(temp1, _a(x), _b(y))
Mpz_mul(temp2, _b(x), _a(y))
Mpz_add(_a(z), temp1, temp2)
Mpz_mul(temp1, _b(x), _b(y))
Mpz_mul(temp2, _a(x), _a(y))
Mpz_sub(_b(z), temp1, temp2)
mpq_canonicalize(z)
mpq_set(x, z)
End If
End If
Mpz_mul(temp1, _a(y), _b(y))
Mpz_mul(temp2, _b(y), _a(y))
Mpz_add(_a(z), temp1, temp2)
Mpz_mul(temp1, _b(y), _b(y))
Mpz_mul(temp2, _a(y), _a(y))
Mpz_sub(_b(z), temp1, temp2)
mpq_canonicalize(z)
mpq_set(y, z)
a = a Shr 1
Wend
mpq_set(f1, x)
End Sub
' ------=< MAIN >=------
Dim As Mpq_ptr f1, f2, f3
f1 = Allocate(Len(__mpq_struct)) : Mpq_init(f1)
f2 = Allocate(Len(__mpq_struct)) : Mpq_init(f2)
f3 = Allocate(Len(__mpq_struct)) : Mpq_init(f3)
Dim As Mpz_ptr temp1, temp2
temp1 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp1)
temp2 = Allocate(Len(__Mpz_struct)) : Mpz_init(temp2)
Dim As mpf_ptr float
float = Allocate(Len(__mpf_struct)) : Mpf_init(float)
Dim As LongInt m1, a1, b1, flag, t1, t2, t3, t4
Dim As String s, s1, s2, s3, sign
Dim As ZString Ptr zstr
Do
Read s
If s = "" Then Exit Do
flag = -1
While s <> ""
t1 = InStr(s, "[") +1
t2 = InStr(t1, s, ",") +1
t3 = InStr(t2, s, ",") +1
t4 = InStr(t3, s, "]")
s1 = Trim(Mid(s, t1, t2 - t1 -1))
s2 = Trim(Mid(s, t2, t3 - t2 -1))
s3 = Trim(Mid(s, t3, t4 - t3))
m1 = Val(s1)
a1 = Val(s2)
b1 = Val(s3)
sign = IIf(m1 < 0, " - ", " + ")
If m1 < 0 Then a1 = -a1 : m1 = Abs(m1)
s = Mid(s, t4 +1)
Print IIf(flag = 0, sign, ""); IIf(m1 = 1, "", Str(m1));
Print "Atn("; s2; "/" ;s3; ")";
If flag = -1 Then
flag = 0
Mpz_set_si(_a(f1), a1)
Mpz_set_si(_b(f1), b1)
If m1 > 1 Then work2do(m1, f1)
Continue While
End If
Mpz_set_si(_a(f2), a1)
Mpz_set_si(_b(f2), b1)
If m1 > 1 Then work2do(m1, f2)
Mpz_mul(temp1, _a(f1), _b(f2))
Mpz_mul(temp2, _b(f1), _a(f2))
Mpz_add(_a(f3), temp1, temp2)
Mpz_mul(temp1, _b(f1), _b(f2))
Mpz_mul(temp2, _a(f1), _a(f2))
Mpz_sub(_b(f3), temp1, temp2)
mpq_canonicalize(f3)
mpq_set(f1, f3)
Wend
If Mpz_cmp_ui(_b(f1), 1) = 0 AndAlso Mpz_cmp(_a(f1), _b(f1)) = 0 Then
Print " = 1"
Else
Mpf_set_q(float, f1)
gmp_printf(!" = %.*Ff\n", 15, float)
End If
Loop
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
- Output:
Atn(1/2) + Atn(1/3) = 1 2Atn(1/3) + Atn(1/7) = 1 4Atn(1/5) - Atn(1/239) = 1 5Atn(1/7) + 2Atn(3/79) = 1 Atn(1/2) + Atn(1/5) + Atn(1/8) = 1 4Atn(1/5) - Atn(1/70) + Atn(1/99) = 1 5Atn(1/7) + 4Atn(1/53) + 2Atn(1/4443) = 1 6Atn(1/8) + 2Atn(1/57) + Atn(1/239) = 1 8Atn(1/10) - Atn(1/239) - 4Atn(1/515) = 1 12Atn(1/18) + 8Atn(1/57) - 5Atn(1/239) = 1 16Atn(1/21) + 3Atn(1/239) + 4Atn(3/1042) = 1 22Atn(1/28) + 2Atn(1/443) - 5Atn(1/1393) - 10Atn(1/11018) = 1 22Atn(1/38) + 17Atn(7/601) + 10Atn(7/8149) = 1 44Atn(1/57) + 7Atn(1/239) - 12Atn(1/682) + 24Atn(1/12943) = 1 88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12943) = 1 88Atn(1/172) + 51Atn(1/239) + 32Atn(1/682) + 44Atn(1/5357) + 68Atn(1/12944) = 0.999999188225744
Visual Basic .NET
BigRat class based on the Arithmetic/Rational#C here at Rosetta Code.
The parser here allows for some flexibility in the input text. Case is ignored, and a variable number of spaces are allowed. Atan(), arctan(), atn() are all recognized as valid. If one of those three are not found, a warning will appear. The coefficient need not have a multiplication sign between it and the "arctan()". The left side of the equation must be pi / 4, otherwise a warning will appear.
Imports System.Numerics
Public Class BigRat ' Big Rational Class constructed with BigIntegers
Implements IComparable
Public nu, de As BigInteger
Public Shared Zero = New BigRat(BigInteger.Zero, BigInteger.One),
One = New BigRat(BigInteger.One, BigInteger.One)
Sub New(bRat As BigRat)
nu = bRat.nu : de = bRat.de
End Sub
Sub New(n As BigInteger, d As BigInteger)
If d = BigInteger.Zero Then _
Throw (New Exception(String.Format("tried to set a BigRat with ({0}/{1})", n, d)))
Dim bi As BigInteger = BigInteger.GreatestCommonDivisor(n, d)
If bi > BigInteger.One Then n /= bi : d /= bi
If d < BigInteger.Zero Then n = -n : d = -d
nu = n : de = d
End Sub
Shared Operator -(x As BigRat) As BigRat
Return New BigRat(-x.nu, x.de)
End Operator
Shared Operator +(x As BigRat, y As BigRat)
Return New BigRat(x.nu * y.de + x.de * y.nu, x.de * y.de)
End Operator
Shared Operator -(x As BigRat, y As BigRat) As BigRat
Return x + (-y)
End Operator
Shared Operator *(x As BigRat, y As BigRat) As BigRat
Return New BigRat(x.nu * y.nu, x.de * y.de)
End Operator
Shared Operator /(x As BigRat, y As BigRat) As BigRat
Return New BigRat(x.nu * y.de, x.de * y.nu)
End Operator
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
Dim dif As BigRat = New BigRat(nu, de) - obj
If dif.nu < BigInteger.Zero Then Return -1
If dif.nu > BigInteger.Zero Then Return 1
Return 0
End Function
Shared Operator =(x As BigRat, y As BigRat) As Boolean
Return x.CompareTo(y) = 0
End Operator
Shared Operator <>(x As BigRat, y As BigRat) As Boolean
Return x.CompareTo(y) <> 0
End Operator
Overrides Function ToString() As String
If de = BigInteger.One Then Return nu.ToString
Return String.Format("({0}/{1})", nu, de)
End Function
Shared Function Combine(a As BigRat, b As BigRat) As BigRat
Return (a + b) / (BigRat.One - (a * b))
End Function
End Class
Public Structure Term ' coefficent, BigRational construction for each term
Dim c As Integer, br As BigRat
Sub New(cc As Integer, bigr As BigRat)
c = cc : br = bigr
End Sub
End Structure
Module Module1
Function Eval(c As Integer, x As BigRat) As BigRat
If c = 1 Then Return x Else If c < 0 Then Return Eval(-c, -x)
Dim hc As Integer = c \ 2
Return BigRat.Combine(Eval(hc, x), Eval(c - hc, x))
End Function
Function Sum(terms As List(Of Term)) As BigRat
If terms.Count = 1 Then Return Eval(terms(0).c, terms(0).br)
Dim htc As Integer = terms.Count / 2
Return BigRat.Combine(Sum(terms.Take(htc).ToList), Sum(terms.Skip(htc).ToList))
End Function
Function ParseLine(ByVal s As String) As List(Of Term)
ParseLine = New List(Of Term) : Dim t As String = s.ToLower, p As Integer, x As New Term(1, BigRat.Zero)
While t.Contains(" ") : t = t.Replace(" ", "") : End While
p = t.IndexOf("pi/4=") : If p < 0 Then _
Console.WriteLine("warning: tan(left side of equation) <> 1") : ParseLine.Add(x) : Exit Function
t = t.Substring(p + 5)
For Each item As String In t.Split(")")
If item.Length > 5 Then
If (Not item.Contains("tan") OrElse item.IndexOf("a") < 0 OrElse
item.IndexOf("a") > item.IndexOf("tan")) AndAlso Not item.Contains("atn") Then
Console.WriteLine("warning: a term is mising a valid arctangent identifier on the right side of the equation: [{0})]", item)
ParseLine = New List(Of Term) : ParseLine.Add(New Term(1, BigRat.Zero)) : Exit Function
End If
x.c = 1 : x.br = New BigRat(BigRat.One)
p = item.IndexOf("/") : If p > 0 Then
x.br.de = UInt64.Parse(item.Substring(p + 1))
item = item.Substring(0, p)
p = item.IndexOf("(") : If p > 0 Then
x.br.nu = UInt64.Parse(item.Substring(p + 1))
p = item.IndexOf("a") : If p > 0 Then
Integer.TryParse(item.Substring(0, p).Replace("*", ""), x.c)
If x.c = 0 Then x.c = 1
If item.Contains("-") AndAlso x.c > 0 Then x.c = -x.c
End If
ParseLine.Add(x)
End If
End If
End If
Next
End Function
Sub Main(ByVal args As String())
Dim nl As String = vbLf
For Each item In ("pi/4 = ATan(1 / 2) + ATan(1/3)" & nl &
"pi/4 = 2Atan(1/3) + ATan(1/7)" & nl &
"pi/4 = 4ArcTan(1/5) - ATan(1 / 239)" & nl &
"pi/4 = 5arctan(1/7) + 2 * atan(3/79)" & nl &
"Pi/4 = 5ATan(29/278) + 7*ATan(3/79)" & nl &
"pi/4 = atn(1/2) + ATan(1/5) + ATan(1/8)" & nl &
"PI/4 = 4ATan(1/5) - Atan(1/70) + ATan(1/99)" & nl &
"pi /4 = 5*ATan(1/7) + 4 ATan(1/53) + 2ATan(1/4443)" & nl &
"pi / 4 = 6ATan(1/8) + 2arctangent(1/57) + ATan(1/239)" & nl &
"pi/ 4 = 8ATan(1/10) - ATan(1/239) - 4ATan(1/515)" & nl &
"pi/4 = 12ATan(1/18) + 8ATan(1/57) - 5ATan(1/239)" & nl &
"pi/4 = 16 * ATan(1/21) + 3ATan(1/239) + 4ATan(3/1042)" & nl &
"pi/4 = 22ATan(1/28) + 2ATan(1/443) - 5ATan(1/1393) - 10 ATan( 1 / 11018 )" & nl &
"pi/4 = 22ATan(1/38) + 17ATan(7/601) + 10ATan(7 / 8149)" & nl &
"pi/4 = 44ATan(1/57) + 7ATan(1/239) - 12ATan(1/682) + 24ATan(1/12943)" & nl &
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12943)" & nl &
"pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12944)").Split(nl)
Console.WriteLine("{0}: {1}", If(Sum(ParseLine(item)) = BigRat.One, "Pass", "Fail"), item)
Next
End Sub
End Module
- Output:
Pass: pi/4 = ATan(1 / 2) + ATan(1/3) Pass: pi/4 = 2Atan(1/3) + ATan(1/7) Pass: pi/4 = 4ArcTan(1/5) - ATan(1 / 239) Pass: pi/4 = 5arctan(1/7) + 2 * atan(3/79) Pass: pi/4 = 5ATan(29/278) + 7*ATan(3/79) Pass: pi/4 = atn(1/2) + ATan(1/5) + ATan(1/8) Pass: pi/4 = 4ATan(1/5) - Atan(1/70) + ATan(1/99) Pass: pi /4 = 5*ATan(1/7) + 4 ATan(1/53) + 2ATan(1/4443) Pass: pi / 4 = 6ATan(1/8) + 2arctangent(1/57) + ATan(1/239) Pass: pi/ 4 = 8ATan(1/10) - ATan(1/239) - 4ATan(1/515) Pass: pi/4 = 12ATan(1/18) + 8ATan(1/57) - 5ATan(1/239) Pass: pi/4 = 16 * ATan(1/21) + 3ATan(1/239) + 4ATan(3/1042) Pass: pi/4 = 22ATan(1/28) + 2ATan(1/443) - 5ATan(1/1393) - 10 ATan( 1 / 11018 ) Pass: pi/4 = 22ATan(1/38) + 17ATan(7/601) + 10ATan(7 / 8149) Pass: pi/4 = 44ATan(1/57) + 7ATan(1/239) - 12ATan(1/682) + 24ATan(1/12943) Pass: pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12943) Fail: pi/4 = 88ATan(1/172) + 51ATan(1/239) + 32ATan(1/682) + 44ATan(1/5357) + 68ATan(1/12944)
Clojure
Clojure automatically handles ratio of numbers as fractions
(ns tanevaulator
(:gen-class))
;; Notation: [a b c] -> a x arctan(a/b)
(def test-cases [
[[1, 1, 2], [1, 1, 3]],
[[2, 1, 3], [1, 1, 7]],
[[4, 1, 5], [-1, 1, 239]],
[[5, 1, 7], [2, 3, 79]],
[[1, 1, 2], [1, 1, 5], [1, 1, 8]],
[[4, 1, 5], [-1, 1, 70], [1, 1, 99]],
[[5, 1, 7], [4, 1, 53], [2, 1, 4443]],
[[6, 1, 8], [2, 1, 57], [1, 1, 239]],
[[8, 1, 10], [-1, 1, 239], [-4, 1, 515]],
[[12, 1, 18], [8, 1, 57], [-5, 1, 239]],
[[16, 1, 21], [3, 1, 239], [4, 3, 1042]],
[[22, 1, 28], [2, 1, 443], [-5, 1, 1393], [-10, 1, 11018]],
[[22, 1, 38], [17, 7, 601], [10, 7, 8149]],
[[44, 1, 57], [7, 1, 239], [-12, 1, 682], [24, 1, 12943]],
[[88, 1, 172], [51, 1, 239], [32, 1, 682], [44, 1, 5357], [68, 1, 12943]],
[[88, 1, 172], [51, 1, 239], [32, 1, 682], [44, 1, 5357], [68, 1, 12944]]
])
(defn tan-sum [a b]
" tan (a + b) "
(/ (+ a b) (- 1 (* a b))))
(defn tan-eval [m]
" Evaluates tan of a triplet (e.g. [1, 1, 2])"
(let [coef (first m)
rat (/ (nth m 1) (nth m 2))]
(cond
(= 1 coef) rat
(neg? coef) (tan-eval [(- (nth m 0)) (- (nth m 1)) (nth m 2)])
:else (let [
ca (quot coef 2)
cb (- coef ca)
a (tan-eval [ca (nth m 1) (nth m 2)])
b (tan-eval [cb (nth m 1) (nth m 2)])]
(tan-sum a b)))))
(defn tans [m]
" Evaluates tan of set of triplets (e.g. [[1, 1, 2], [1, 1, 3]])"
(if (= 1 (count m))
(tan-eval (nth m 0))
(let [a (tan-eval (first m))
b (tans (rest m))]
(tan-sum a b))))
(doseq [q test-cases]
" Display results "
(println "tan " q " = "(tans q)))
- Output:
tan [[1 1 2] [1 1 3]] = 1N tan [[2 1 3] [1 1 7]] = 1N tan [[4 1 5] [-1 1 239]] = 1N tan [[5 1 7] [2 3 79]] = 1N tan [[1 1 2] [1 1 5] [1 1 8]] = 1N tan [[4 1 5] [-1 1 70] [1 1 99]] = 1N tan [[5 1 7] [4 1 53] [2 1 4443]] = 1N tan [[6 1 8] [2 1 57] [1 1 239]] = 1N tan [[8 1 10] [-1 1 239] [-4 1 515]] = 1N tan [[12 1 18] [8 1 57] [-5 1 239]] = 1N tan [[16 1 21] [3 1 239] [4 3 1042]] = 1N tan [[22 1 28] [2 1 443] [-5 1 1393] [-10 1 11018]] = 1N tan [[22 1 38] [17 7 601] [10 7 8149]] = 1N tan [[44 1 57] [7 1 239] [-12 1 682] [24 1 12943]] = 1N tan [[88 1 172] [51 1 239] [32 1 682] [44 1 5357] [68 1 12943]] = 1N tan [[88 1 172] [51 1 239] [32 1 682] [44 1 5357] [68 1 12944]] = 1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223 / 1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711 (equals 0.9999991882257445)
D
This uses the module of the Arithmetic Rational Task.
import std.stdio, std.regex, std.conv, std.string, std.range,
arithmetic_rational;
struct Pair { int x; Rational r; }
Pair[][] parseEquations(in string text) /*pure nothrow*/ {
auto r = regex(r"\s*(?P<sign>[+-])?\s*(?:(?P<mul>\d+)\s*\*)?\s*" ~
r"arctan\((?P<num>\d+)/(?P<denom>\d+)\)");
Pair[][] machins;
foreach (const line; text.splitLines) {
Pair[] formula;
foreach (part; line.split("=")[1].matchAll(r)) {
immutable mul = part["mul"],
num = part["num"],
denom = part["denom"];
formula ~= Pair((part["sign"] == "-" ? -1 : 1) *
(mul.empty ? 1 : mul.to!int),
Rational(num.to!int,
denom.empty ? 1 : denom.to!int));
}
machins ~= formula;
}
return machins;
}
Rational tans(in Pair[] xs) pure nothrow {
static Rational tanEval(in int coef, in Rational f)
pure nothrow {
if (coef == 1)
return f;
if (coef < 0)
return -tanEval(-coef, f);
immutable a = tanEval(coef / 2, f),
b = tanEval(coef - coef / 2, f);
return (a + b) / (1 - a * b);
}
if (xs.length == 1)
return tanEval(xs[0].tupleof);
immutable a = xs[0 .. $ / 2].tans,
b = xs[$ / 2 .. $].tans;
return (a + b) / (1 - a * b);
}
void main() {
immutable equationText =
"pi/4 = arctan(1/2) + arctan(1/3)
pi/4 = 2*arctan(1/3) + arctan(1/7)
pi/4 = 4*arctan(1/5) - arctan(1/239)
pi/4 = 5*arctan(1/7) + 2*arctan(3/79)
pi/4 = 5*arctan(29/278) + 7*arctan(3/79)
pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)
pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)
pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)
pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)
pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)
pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)
pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)
pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)
pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)
pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)";
const machins = equationText.parseEquations;
foreach (const machin, const eqn; machins.zip(equationText.splitLines)) {
immutable ans = machin.tans;
writefln("%5s: %s", ans == 1 ? "OK" : "ERROR", eqn);
}
}
- Output:
OK: pi/4 = arctan(1/2) + arctan(1/3) OK: pi/4 = 2*arctan(1/3) + arctan(1/7) OK: pi/4 = 4*arctan(1/5) - arctan(1/239) OK: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) OK: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) OK: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) OK: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) OK: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) OK: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) OK: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) OK: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) OK: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) OK: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) OK: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) OK: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
EchoLisp
(lib 'math)
(lib 'match)
(math-precision 1.e-10)
;; formally derive (tan ..) expressions
;; copied from Racket
;; adapted and improved for performance
(define (reduce e)
;; (set! rcount (1+ rcount)) ;; # of calls
(match e
[(? number? a) a]
[('+ (? number? a) (? number? b)) (+ a b)]
[('- (? number? a) (? number? b)) (- a b)]
[('- (? number? a)) (- a)]
[('* (? number? a) (? number? b)) (* a b)]
[('/ (? number? a) (? number? b)) (/ a b)] ; patch
[( '+ a b) (reduce `(+ ,(reduce a) ,(reduce b)))]
[( '- a b) (reduce `(- ,(reduce a) ,(reduce b)))]
[( '- a) (reduce `(- ,(reduce a)))]
[( '* a b) (reduce `(* ,(reduce a) ,(reduce b)))]
[( '/ a b) (reduce `(/ ,(reduce a) ,(reduce b)))]
[( 'tan ('arctan a)) (reduce a)]
[( 'tan ( '- a)) (reduce `(- (tan ,a)))]
;; x 100 # calls reduction : derive (tan ,a) only once
[( 'tan ( '+ a b))
(let ((alpha (reduce `(tan ,a))) (beta (reduce `(tan ,b))))
(reduce `(/ (+ ,alpha ,beta) (- 1 (* ,alpha ,beta)))))]
[( 'tan ( '+ a b c ...)) (reduce `(tan (+ ,a (+ ,b ,@c))))]
[( 'tan ( '- a b))
(let ((alpha (reduce `(tan ,a))) (beta (reduce `(tan ,b))))
(reduce `(/ (- ,alpha ,beta) (+ 1 (* ,alpha ,beta)))))]
;; add formula for (tan 2 (arctan a)) = 2 a / (1 - a^2))
[( 'tan ( '* 2 ('arctan a))) (reduce `(/ (* 2 ,a) (- 1 (* ,a ,a))))]
[( 'tan ( '* 1 ('arctan a))) (reduce a)] ; added
[( 'tan ( '* (? number? n) a))
(cond [(< n 0) (reduce `(- (tan (* ,(- n) ,a))))]
[(= n 0) 0]
[(= n 1) (reduce `(tan ,a))]
[(even? n)
(let ((alpha (reduce `(tan (* ,(/ n 2) ,a))))) ;; # calls reduction
(reduce `(/ (* 2 ,alpha) (- 1 (* ,alpha ,alpha)))))]
[else (reduce `(tan (+ ,a (* ,(- n 1) ,a))))])]
))
(define (task)
(for ((f machins))
(if (~= 1 (reduce f))
(writeln '👍 f '⟾ 1 )
(writeln '❌ f '➽ (reduce f) ))))
- Output:
(define machins
'((tan (+ (arctan 1/2) (arctan 1/3)))
(tan (+ (* 2 (arctan 1/3)) (arctan 1/7)))
(tan (- (* 4 (arctan 1/5)) (arctan 1/239)))
(tan (+ (* 5 (arctan 1/7)) (* 2 (arctan 3/79))))
(tan (+ (* 5 (arctan 29/278)) (* 7 (arctan 3/79))))
(tan (+ (arctan 1/2) (arctan 1/5) (arctan 1/8)))
(tan (+ (* 4 (arctan 1/5)) (* -1 (arctan 1/70)) (arctan 1/99)))
(tan (+ (* 5 (arctan 1/7)) (* 4 (arctan 1/53)) (* 2 (arctan 1/4443))))
(tan (+ (* 6 (arctan 1/8)) (* 2 (arctan 1/57)) (arctan 1/239)))
(tan (+ (* 8 (arctan 1/10)) (* -1 (arctan 1/239)) (* -4 (arctan 1/515))))
(tan (+ (* 12 (arctan 1/18)) (* 8 (arctan 1/57)) (* -5 (arctan 1/239))))
(tan (+ (* 16 (arctan 1/21)) (* 3 (arctan 1/239)) (* 4 (arctan 3/1042))))
(tan (+ (* 22 (arctan 1/28)) (* 2 (arctan 1/443)) (* -5 (arctan 1/1393)) (* -10 (arctan 1/11018))))
(tan (+ (* 22 (arctan 1/38)) (* 17 (arctan 7/601)) (* 10 (arctan 7/8149))))
(tan (+ (* 44 (arctan 1/57)) (* 7 (arctan 1/239)) (* -12 (arctan 1/682)) (* 24 (arctan 1/12943))))
(tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12943))))
(tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12944))))))
(task)
👍 (tan (+ (arctan 1/2) (arctan 1/3))) ⟾ 1
👍 (tan (+ (* 2 (arctan 1/3)) (arctan 1/7))) ⟾ 1
👍 (tan (- (* 4 (arctan 1/5)) (arctan 1/239))) ⟾ 1
👍 (tan (+ (* 5 (arctan 1/7)) (* 2 (arctan 3/79)))) ⟾ 1
👍 (tan (+ (* 5 (arctan 29/278)) (* 7 (arctan 3/79)))) ⟾ 1
👍 (tan (+ (arctan 1/2) (arctan 1/5) (arctan 1/8))) ⟾ 1
👍 (tan (+ (* 4 (arctan 1/5)) (* -1 (arctan 1/70)) (arctan 1/99))) ⟾ 1
👍 (tan (+ (* 5 (arctan 1/7)) (* 4 (arctan 1/53)) (* 2 (arctan 1/4443)))) ⟾ 1
👍 (tan (+ (* 6 (arctan 1/8)) (* 2 (arctan 1/57)) (arctan 1/239))) ⟾ 1
👍 (tan (+ (* 8 (arctan 1/10)) (* -1 (arctan 1/239)) (* -4 (arctan 1/515)))) ⟾ 1
👍 (tan (+ (* 12 (arctan 1/18)) (* 8 (arctan 1/57)) (* -5 (arctan 1/239)))) ⟾ 1
👍 (tan (+ (* 16 (arctan 1/21)) (* 3 (arctan 1/239)) (* 4 (arctan 3/1042)))) ⟾ 1
👍 (tan (+ (* 22 (arctan 1/28)) (* 2 (arctan 1/443)) (* -5 (arctan 1/1393)) (* -10 (arctan 1/11018)))) ⟾ 1
👍 (tan (+ (* 22 (arctan 1/38)) (* 17 (arctan 7/601)) (* 10 (arctan 7/8149)))) ⟾ 1
👍 (tan (+ (* 44 (arctan 1/57)) (* 7 (arctan 1/239)) (* -12 (arctan 1/682)) (* 24 (arctan 1/12943)))) ⟾ 1
👍 (tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12943)))) ⟾ 1
❌ (tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12944)))) ➽ 0.9999991882257442
Factor
USING: combinators formatting kernel locals math sequences ;
IN: rosetta-code.machin
: tan+ ( x y -- z ) [ + ] [ * 1 swap - / ] 2bi ;
:: tan-eval ( coef frac -- x )
{
{ [ coef zero? ] [ 0 ] }
{ [ coef neg? ] [ coef neg frac tan-eval neg ] }
{ [ coef odd? ] [ frac coef 1 - frac tan-eval tan+ ] }
[ coef 2/ frac tan-eval dup tan+ ]
} cond ;
: tans ( seq -- x ) [ first2 tan-eval ] [ tan+ ] map-reduce ;
: machin ( -- )
{
{ { 1 1/2 } { 1 1/3 } }
{ { 2 1/3 } { 1 1/7 } }
{ { 4 1/5 } { -1 1/239 } }
{ { 5 1/7 } { 2 3/79 } }
{ { 5 29/278 } { 7 3/79 } }
{ { 1 1/2 } { 1 1/5 } { 1 1/8 } }
{ { 5 1/7 } { 4 1/53 } { 2 1/4443 } }
{ { 6 1/8 } { 2 1/57 } { 1 1/239 } }
{ { 8 1/10 } { -1 1/239 } { -4 1/515 } }
{ { 12 1/18 } { 8 1/57 } { -5 1/239 } }
{ { 16 1/21 } { 3 1/239 } { 4 3/1042 } }
{ { 22 1/28 } { 2 1/443 }
{ -5 1/1393 } { -10 1/11018 } }
{ { 22 1/38 } { 17 7/601 } { 10 7/8149 } }
{ { 44 1/57 } { 7 1/239 } { -12 1/682 } { 24 1/12943 } }
{ { 88 1/172 } { 51 1/239 } { 32 1/682 }
{ 44 1/5357 } { 68 1/12943 } }
{ { 88 1/172 } { 51 1/239 } { 32 1/682 }
{ 44 1/5357 } { 68 1/12944 } }
} [ dup tans "tan %u = %u\n" printf ] each ;
MAIN: machin
- Output:
tan { { 1 1/2 } { 1 1/3 } } = 1 tan { { 2 1/3 } { 1 1/7 } } = 1 tan { { 4 1/5 } { -1 1/239 } } = 1 tan { { 5 1/7 } { 2 3/79 } } = 1 tan { { 5 29/278 } { 7 3/79 } } = 1 tan { { 1 1/2 } { 1 1/5 } { 1 1/8 } } = 1 tan { { 5 1/7 } { 4 1/53 } { 2 1/4443 } } = 1 tan { { 6 1/8 } { 2 1/57 } { 1 1/239 } } = 1 tan { { 8 1/10 } { -1 1/239 } { -4 1/515 } } = 1 tan { { 12 1/18 } { 8 1/57 } { -5 1/239 } } = 1 tan { { 16 1/21 } { 3 1/239 } { 4 3/1042 } } = 1 tan { { 22 1/28 } { 2 1/443 } { -5 1/1393 } { -10 1/11018 } } = 1 tan { { 22 1/38 } { 17 7/601 } { 10 7/8149 } } = 1 tan { { 44 1/57 } { 7 1/239 } { -12 1/682 } { 24 1/12943 } } = 1 tan { { 88 1/172 } { 51 1/239 } { 32 1/682 } { 44 1/5357 } { 68 1/12943 } } = 1 tan { { 88 1/172 } { 51 1/239 } { 32 1/682 } { 44 1/5357 } { 68 1/12944 } } = 10092...08223/10092...39711
GAP
The formula is entered as a list of pairs [k, x], where each pair means k*atan(x), and all the terms in the list are summed. Like most other solutions, the program will only check that the tangent of the resulting sum is 1. For instance, Check([[5, 1/2], [5, 1/3]]);
returns also true
, though the result is 5pi/4.
TanPlus := function(a, b)
return (a + b) / (1 - a * b);
end;
TanTimes := function(n, a)
local x;
x := 0;
while n > 0 do
if IsOddInt(n) then
x := TanPlus(x, a);
fi;
a := TanPlus(a, a);
n := QuoInt(n, 2);
od;
return x;
end;
Check := function(a)
local x, p;
x := 0;
for p in a do
x := TanPlus(x, SignInt(p[1]) * TanTimes(AbsInt(p[1]), p[2]));
od;
return x = 1;
end;
ForAll([
[[1, 1/2], [1, 1/3]],
[[2, 1/3], [1, 1/7]],
[[4, 1/5], [-1, 1/239]],
[[5, 1/7], [2, 3/79]],
[[5, 29/278], [7, 3/79]],
[[1, 1/2], [1, 1/5], [1, 1/8]],
[[5, 1/7], [4, 1/53], [2, 1/4443]],
[[6, 1/8], [2, 1/57], [1, 1/239]],
[[8, 1/10], [-1, 1/239], [-4, 1/515]],
[[12, 1/18], [8, 1/57], [-5, 1/239]],
[[16, 1/21], [3, 1/239], [4, 3/1042]],
[[22, 1/28], [2, 1/443], [-5, 1/1393], [-10, 1/11018]],
[[22, 1/38], [17, 7/601], [10, 7/8149]],
[[44, 1/57], [7, 1/239], [-12, 1/682], [24, 1/12943]],
[[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12943]]], Check);
Check([[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]);
Go
package main
import (
"fmt"
"math/big"
)
type mTerm struct {
a, n, d int64
}
var testCases = [][]mTerm{
{{1, 1, 2}, {1, 1, 3}},
{{2, 1, 3}, {1, 1, 7}},
{{4, 1, 5}, {-1, 1, 239}},
{{5, 1, 7}, {2, 3, 79}},
{{1, 1, 2}, {1, 1, 5}, {1, 1, 8}},
{{4, 1, 5}, {-1, 1, 70}, {1, 1, 99}},
{{5, 1, 7}, {4, 1, 53}, {2, 1, 4443}},
{{6, 1, 8}, {2, 1, 57}, {1, 1, 239}},
{{8, 1, 10}, {-1, 1, 239}, {-4, 1, 515}},
{{12, 1, 18}, {8, 1, 57}, {-5, 1, 239}},
{{16, 1, 21}, {3, 1, 239}, {4, 3, 1042}},
{{22, 1, 28}, {2, 1, 443}, {-5, 1, 1393}, {-10, 1, 11018}},
{{22, 1, 38}, {17, 7, 601}, {10, 7, 8149}},
{{44, 1, 57}, {7, 1, 239}, {-12, 1, 682}, {24, 1, 12943}},
{{88, 1, 172}, {51, 1, 239}, {32, 1, 682}, {44, 1, 5357}, {68, 1, 12943}},
{{88, 1, 172}, {51, 1, 239}, {32, 1, 682}, {44, 1, 5357}, {68, 1, 12944}},
}
func main() {
for _, m := range testCases {
fmt.Printf("tan %v = %v\n", m, tans(m))
}
}
var one = big.NewRat(1, 1)
func tans(m []mTerm) *big.Rat {
if len(m) == 1 {
return tanEval(m[0].a, big.NewRat(m[0].n, m[0].d))
}
half := len(m) / 2
a := tans(m[:half])
b := tans(m[half:])
r := new(big.Rat)
return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b)))
}
func tanEval(coef int64, f *big.Rat) *big.Rat {
if coef == 1 {
return f
}
if coef < 0 {
r := tanEval(-coef, f)
return r.Neg(r)
}
ca := coef / 2
cb := coef - ca
a := tanEval(ca, f)
b := tanEval(cb, f)
r := new(big.Rat)
return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b)))
}
- Output:
Last line edited to show only most significant digits of fraction which is near, but not exactly equal to 1.
tan [{1 1 2} {1 1 3}] = 1/1 tan [{2 1 3} {1 1 7}] = 1/1 tan [{4 1 5} {-1 1 239}] = 1/1 tan [{5 1 7} {2 3 79}] = 1/1 tan [{1 1 2} {1 1 5} {1 1 8}] = 1/1 tan [{4 1 5} {-1 1 70} {1 1 99}] = 1/1 tan [{5 1 7} {4 1 53} {2 1 4443}] = 1/1 tan [{6 1 8} {2 1 57} {1 1 239}] = 1/1 tan [{8 1 10} {-1 1 239} {-4 1 515}] = 1/1 tan [{12 1 18} {8 1 57} {-5 1 239}] = 1/1 tan [{16 1 21} {3 1 239} {4 3 1042}] = 1/1 tan [{22 1 28} {2 1 443} {-5 1 1393} {-10 1 11018}] = 1/1 tan [{22 1 38} {17 7 601} {10 7 8149}] = 1/1 tan [{44 1 57} {7 1 239} {-12 1 682} {24 1 12943}] = 1/1 tan [{88 1 172} {51 1 239} {32 1 682} {44 1 5357} {68 1 12943}] = 1/1 tan [{88 1 172} {51 1 239} {32 1 682} {44 1 5357} {68 1 12944}] = 100928801... / 100928883...
Haskell
import Data.Ratio
import Data.List (foldl')
tanPlus :: Fractional a => a -> a -> a
tanPlus a b = (a + b) / (1 - a * b)
tanEval :: (Integral a, Fractional b) => (a, b) -> b
tanEval (0,_) = 0
tanEval (coef,f)
| coef < 0 = -tanEval (-coef, f)
| odd coef = tanPlus f $ tanEval (coef - 1, f)
| otherwise = tanPlus a a
where a = tanEval (coef `div` 2, f)
tans :: (Integral a, Fractional b) => [(a, b)] -> b
tans = foldl' tanPlus 0 . map tanEval
machins = [
[(1, 1%2), (1, 1%3)],
[(2, 1%3), (1, 1%7)],
[(12, 1%18), (8, 1%57), (-5, 1%239)],
[(88, 1%172), (51, 1%239), (32 , 1%682), (44, 1%5357), (68, 1%12943)]]
not_machin = [(88, 1%172), (51, 1%239), (32 , 1%682), (44, 1%5357), (68, 1%12944)]
main = do
putStrLn "Machins:"
mapM_ (\x -> putStrLn $ show (tans x) ++ " <-- " ++ show x) machins
putStr "\nnot Machin: "; print not_machin
print (tans not_machin)
A crazier way to do the above, exploiting the built-in exponentiation algorithms:
import Data.Ratio
-- Private type. Do not use outside of the tans function
newtype Tan a = Tan a deriving (Eq, Show)
instance Fractional a => Num (Tan a) where
_ + _ = undefined
Tan a * Tan b = Tan $ (a + b) / (1 - a * b)
negate _ = undefined
abs _ = undefined
signum _ = undefined
fromInteger 1 = Tan 0 -- identity for the (*) above
fromInteger _ = undefined
instance Fractional a => Fractional (Tan a) where
fromRational _ = undefined
recip (Tan f) = Tan (-f) -- inverse for the (*) above
tans :: (Integral a, Fractional b) => [(a, b)] -> b
tans xs = x where
Tan x = product [Tan f ^^ coef | (coef,f) <- xs]
machins = [
[(1, 1%2), (1, 1%3)],
[(2, 1%3), (1, 1%7)],
[(12, 1%18), (8, 1%57), (-5, 1%239)],
[(88, 1%172), (51, 1%239), (32 , 1%682), (44, 1%5357), (68, 1%12943)]]
not_machin = [(88, 1%172), (51, 1%239), (32 , 1%682), (44, 1%5357), (68, 1%12944)]
main = do
putStrLn "Machins:"
mapM_ (\x -> putStrLn $ show (tans x) ++ " <-- " ++ show x) machins
putStr "\nnot Machin: "; print not_machin
print (tans not_machin)
J
Solution:
machin =: 1r4p1 = [: +/ ({. * _3 o. %/@:}.)"1@:x:
Example (test cases from task description):
R =: <@:(0&".);._2 ];._2 noun define
1 1 2
1 1 3
------------
2 1 3
1 1 7
------------
4 1 5
_1 1 239
------------
5 1 7
2 3 79
------------
5 29 278
7 3 79
------------
1 1 2
1 1 5
1 1 8
------------
4 1 5
_1 1 70
1 1 99
------------
5 1 7
4 1 53
2 1 4443
------------
6 1 8
2 1 57
1 1 239
------------
8 1 10
_1 1 239
_4 1 515
------------
12 1 18
8 1 57
_5 1 239
------------
16 1 21
3 1 239
4 3 1042
------------
22 1 28
2 1 443
_5 1 1393
_10 1 11018
------------
22 1 38
17 7 601
10 7 8149
------------
44 1 57
7 1 239
_12 1 682
24 1 12943
------------
88 1 172
51 1 239
32 1 682
44 1 5357
68 1 12943
------------
)
machin&> R
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Example (counterexample):
counterExample=. 12944 (<_1;_1)} >{:R
counterExample NB. Same as final test case with 12943 incremented to 12944
88 1 172
51 1 239
32 1 682
44 1 5357
68 1 12944
machin counterExample
0
Notes: The function machin compares the results of each formula to π/4 (expressed as 1r4p1 in J's numeric notation). The first example above shows the results of these comparisons for each formula (with 1 for true and 0 for false). In J, arctan is expressed as _3 o. values and the function x: coerces values to exact representation; thereafter J will maintain exactness throughout its calculations, as long as it can.
Java
Read formula from file. Parse and evaluate formula. Implement Fraction class to support task.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CheckMachinFormula {
private static String FILE_NAME = "MachinFormula.txt";
public static void main(String[] args) {
try {
runPrivate();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void runPrivate() throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(new File(FILE_NAME)));) {
String inLine = null;
while ( (inLine = reader.readLine()) != null ) {
String[] split = inLine.split("=");
System.out.println(tanLeft(split[0].trim()) + " = " + split[1].trim().replaceAll("\\s+", " ") + " = " + tanRight(split[1].trim()));
}
}
}
private static String tanLeft(String formula) {
if ( formula.compareTo("pi/4") == 0 ) {
return "1";
}
throw new RuntimeException("ERROR 104: Unknown left side: " + formula);
}
private static final Pattern ARCTAN_PATTERN = Pattern.compile("(-{0,1}\\d+)\\*arctan\\((\\d+)/(\\d+)\\)");
private static Fraction tanRight(String formula) {
Matcher matcher = ARCTAN_PATTERN.matcher(formula);
List<Term> terms = new ArrayList<>();
while ( matcher.find() ) {
terms.add(new Term(Integer.parseInt(matcher.group(1)), new Fraction(matcher.group(2), matcher.group(3))));
}
return evaluateArctan(terms);
}
private static Fraction evaluateArctan(List<Term> terms) {
if ( terms.size() == 1 ) {
Term term = terms.get(0);
return evaluateArctan(term.coefficient, term.fraction);
}
int size = terms.size();
List<Term> left = terms.subList(0, (size+1) / 2);
List<Term> right = terms.subList((size+1) / 2, size);
return arctanFormula(evaluateArctan(left), evaluateArctan(right));
}
private static Fraction evaluateArctan(int coefficient, Fraction fraction) {
//System.out.println("C = " + coefficient + ", F = " + fraction);
if ( coefficient == 1 ) {
return fraction;
}
else if ( coefficient < 0 ) {
return evaluateArctan(-coefficient, fraction).negate();
}
if ( coefficient % 2 == 0 ) {
Fraction f = evaluateArctan(coefficient/2, fraction);
return arctanFormula(f, f);
}
Fraction a = evaluateArctan(coefficient/2, fraction);
Fraction b = evaluateArctan(coefficient - (coefficient/2), fraction);
return arctanFormula(a, b);
}
private static Fraction arctanFormula(Fraction f1, Fraction f2) {
return f1.add(f2).divide(Fraction.ONE.subtract(f1.multiply(f2)));
}
private static class Fraction {
public static final Fraction ONE = new Fraction("1", "1");
private BigInteger numerator;
private BigInteger denominator;
public Fraction(String num, String den) {
numerator = new BigInteger(num);
denominator = new BigInteger(den);
}
public Fraction(BigInteger num, BigInteger den) {
numerator = num;
denominator = den;
}
public Fraction negate() {
return new Fraction(numerator.negate(), denominator);
}
public Fraction add(Fraction f) {
BigInteger gcd = denominator.gcd(f.denominator);
BigInteger first = numerator.multiply(f.denominator.divide(gcd));
BigInteger second = f.numerator.multiply(denominator.divide(gcd));
return new Fraction(first.add(second), denominator.multiply(f.denominator).divide(gcd));
}
public Fraction subtract(Fraction f) {
return add(f.negate());
}
public Fraction multiply(Fraction f) {
BigInteger num = numerator.multiply(f.numerator);
BigInteger den = denominator.multiply(f.denominator);
BigInteger gcd = num.gcd(den);
return new Fraction(num.divide(gcd), den.divide(gcd));
}
public Fraction divide(Fraction f) {
return multiply(new Fraction(f.denominator, f.numerator));
}
@Override
public String toString() {
if ( denominator.compareTo(BigInteger.ONE) == 0 ) {
return numerator.toString();
}
return numerator + " / " + denominator;
}
}
private static class Term {
private int coefficient;
private Fraction fraction;
public Term(int c, Fraction f) {
coefficient = c;
fraction = f;
}
}
}
- Output:
1 = 1*arctan(1/2) + 1*arctan(1/3) = 1 1 = 2*arctan(1/3) + 1*arctan(1/7) = 1 1 = 4*arctan(1/5) + -1*arctan(1/239) = 1 1 = 5*arctan(1/7) + 2*arctan(3/79) = 1 1 = 5*arctan(29/278) + 7*arctan(3/79) = 1 1 = 1*arctan(1/2) + 1*arctan(1/5) + 1*arctan(1/8) = 1 1 = 4*arctan(1/5) + -1*arctan(1/70) + 1*arctan(1/99) = 1 1 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) = 1 1 = 6*arctan(1/8) + 2*arctan(1/57) + 1*arctan(1/239) = 1 1 = 8*arctan(1/10) + -1*arctan(1/239) + -4*arctan(1/515) = 1 1 = 12*arctan(1/18) + 8*arctan(1/57) + -5*arctan(1/239) = 1 1 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) = 1 1 = 22*arctan(1/28) + 2*arctan(1/443) + -5*arctan(1/1393) + -10*arctan(1/11018) = 1 1 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) = 1 1 = 44*arctan(1/57) + 7*arctan(1/239) + -12*arctan(1/682) + 24*arctan(1/12943) = 1 1 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) = 1 1 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) = 1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223 / 1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711
Julia
using AbstractAlgebra # implements arbitrary precision rationals
tanplus(x,y) = (x + y) / (1 - x * y)
function taneval(coef, frac)
if coef == 0
return 0
elseif coef < 0
return -taneval(-coef, frac)
elseif isodd(coef)
return tanplus(frac, taneval(coef - 1, frac))
else
x = taneval(div(coef, 2), frac)
return tanplus(x, x)
end
end
taneval(tup::Tuple) = taneval(tup[1], tup[2])
tans(v::Vector{Tuple{BigInt, Rational{BigInt}}}) = foldl(tanplus, map(taneval, v), init=0)
const testmats = Dict{Vector{Tuple{BigInt, Rational{BigInt}}}, Bool}([
([(1, 1//2), (1, 1//3)], true), ([(2, 1//3), (1, 1//7)], true),
([(12, 1//18), (8, 1//57), (-5, 1//239)], true),
([(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12943)], true),
([(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12944)], false)])
function runtestmats()
println("Testing matrices:")
for (k, m) in testmats
ans = tans(k)
println((ans == 1) == m ? "Verified as $m: " : "Not Verified as $m: ", "tan $k = $ans")
end
end
runtestmats()
- Output:
Testing matrices: Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(1, 1//2), (1, 1//3)] = 1//1 Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(2, 1//3), (1, 1//7)] = 1//1 Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12943)] = 1//1 Verified as true: tan Tuple{BigInt,Rational{BigInt}}[(12, 1//18), (8, 1//57), (-5, 1//239)] = 1//1 Verified as false: tan Tuple{BigInt,Rational{BigInt}}[(88, 1//172), (51, 1//239), (32, 1//682), (44, 1//5357), (68, 1//12944)] = 1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223//1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711
Kotlin
As the JVM and Kotlin standard libraries lack a BigRational class, I've written one which just provides sufficient functionality to complete this task:
// version 1.1.3
import java.math.BigInteger
val bigZero = BigInteger.ZERO
val bigOne = BigInteger.ONE
class BigRational : Comparable<BigRational> {
val num: BigInteger
val denom: BigInteger
constructor(n: BigInteger, d: BigInteger) {
require(d != bigZero)
var nn = n
var dd = d
if (nn == bigZero) {
dd = bigOne
}
else if (dd < bigZero) {
nn = -nn
dd = -dd
}
val g = nn.gcd(dd)
if (g > bigOne) {
nn /= g
dd /= g
}
num = nn
denom = dd
}
constructor(n: Long, d: Long) : this(BigInteger.valueOf(n), BigInteger.valueOf(d))
operator fun plus(other: BigRational) =
BigRational(num * other.denom + denom * other.num, other.denom * denom)
operator fun unaryMinus() = BigRational(-num, denom)
operator fun minus(other: BigRational) = this + (-other)
operator fun times(other: BigRational) = BigRational(this.num * other.num, this.denom * other.denom)
fun inverse(): BigRational {
require(num != bigZero)
return BigRational(denom, num)
}
operator fun div(other: BigRational) = this * other.inverse()
override fun compareTo(other: BigRational): Int {
val diff = this - other
return when {
diff.num < bigZero -> -1
diff.num > bigZero -> +1
else -> 0
}
}
override fun equals(other: Any?): Boolean {
if (other == null || other !is BigRational) return false
return this.compareTo(other) == 0
}
override fun toString() = if (denom == bigOne) "$num" else "$num/$denom"
companion object {
val ZERO = BigRational(bigZero, bigOne)
val ONE = BigRational(bigOne, bigOne)
}
}
/** represents a term of the form: c * atan(n / d) */
class Term(val c: Long, val n: Long, val d: Long) {
override fun toString() = when {
c == 1L -> " + "
c == -1L -> " - "
c < 0L -> " - ${-c}*"
else -> " + $c*"
} + "atan($n/$d)"
}
val one = BigRational.ONE
fun tanSum(terms: List<Term>): BigRational {
if (terms.size == 1) return tanEval(terms[0].c, BigRational(terms[0].n, terms[0].d))
val half = terms.size / 2
val a = tanSum(terms.take(half))
val b = tanSum(terms.drop(half))
return (a + b) / (one - (a * b))
}
fun tanEval(c: Long, f: BigRational): BigRational {
if (c == 1L) return f
if (c < 0L) return -tanEval(-c, f)
val ca = c / 2
val cb = c - ca
val a = tanEval(ca, f)
val b = tanEval(cb, f)
return (a + b) / (one - (a * b))
}
fun main(args: Array<String>) {
val termsList = listOf(
listOf(Term(1, 1, 2), Term(1, 1, 3)),
listOf(Term(2, 1, 3), Term(1, 1, 7)),
listOf(Term(4, 1, 5), Term(-1, 1, 239)),
listOf(Term(5, 1, 7), Term(2, 3, 79)),
listOf(Term(5, 29, 278), Term(7, 3, 79)),
listOf(Term(1, 1, 2), Term(1, 1, 5), Term(1, 1, 8)),
listOf(Term(4, 1, 5), Term(-1, 1, 70), Term(1, 1, 99)),
listOf(Term(5, 1, 7), Term(4, 1, 53), Term(2, 1, 4443)),
listOf(Term(6, 1, 8), Term(2, 1, 57), Term(1, 1, 239)),
listOf(Term(8, 1, 10), Term(-1, 1, 239), Term(-4, 1, 515)),
listOf(Term(12, 1, 18), Term(8, 1, 57), Term(-5, 1, 239)),
listOf(Term(16, 1, 21), Term(3, 1, 239), Term(4, 3, 1042)),
listOf(Term(22, 1, 28), Term(2, 1, 443), Term(-5, 1, 1393), Term(-10, 1, 11018)),
listOf(Term(22, 1, 38), Term(17, 7, 601), Term(10, 7, 8149)),
listOf(Term(44, 1, 57), Term(7, 1, 239), Term(-12, 1, 682), Term(24, 1, 12943)),
listOf(Term(88, 1, 172), Term(51, 1, 239), Term(32, 1, 682), Term(44, 1, 5357), Term(68, 1, 12943)),
listOf(Term(88, 1, 172), Term(51, 1, 239), Term(32, 1, 682), Term(44, 1, 5357), Term(68, 1, 12944))
)
for (terms in termsList) {
val f = String.format("%-5s << 1 == tan(", tanSum(terms) == one)
print(f)
print(terms[0].toString().drop(3))
for (i in 1 until terms.size) print(terms[i])
println(")")
}
}
- Output:
true << 1 == tan(atan(1/2) + atan(1/3)) true << 1 == tan(2*atan(1/3) + atan(1/7)) true << 1 == tan(4*atan(1/5) - atan(1/239)) true << 1 == tan(5*atan(1/7) + 2*atan(3/79)) true << 1 == tan(5*atan(29/278) + 7*atan(3/79)) true << 1 == tan(atan(1/2) + atan(1/5) + atan(1/8)) true << 1 == tan(4*atan(1/5) - atan(1/70) + atan(1/99)) true << 1 == tan(5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443)) true << 1 == tan(6*atan(1/8) + 2*atan(1/57) + atan(1/239)) true << 1 == tan(8*atan(1/10) - atan(1/239) - 4*atan(1/515)) true << 1 == tan(12*atan(1/18) + 8*atan(1/57) - 5*atan(1/239)) true << 1 == tan(16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042)) true << 1 == tan(22*atan(1/28) + 2*atan(1/443) - 5*atan(1/1393) - 10*atan(1/11018)) true << 1 == tan(22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149)) true << 1 == tan(44*atan(1/57) + 7*atan(1/239) - 12*atan(1/682) + 24*atan(1/12943)) true << 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12943)) false << 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944))
Mathematica / Wolfram Language
Tan[ArcTan[1/2] + ArcTan[1/3]] == 1
Tan[2 ArcTan[1/3] + ArcTan[1/7]] == 1
Tan[4 ArcTan[1/5] - ArcTan[1/239]] == 1
Tan[5 ArcTan[1/7] + 2 ArcTan[3/79]] == 1
Tan[5 ArcTan[29/278] + 7 ArcTan[3/79]] == 1
Tan[ArcTan[1/2] + ArcTan[1/5] + ArcTan[1/8]] == 1
Tan[4 ArcTan[1/5] - ArcTan[1/70] + ArcTan[1/99]] == 1
Tan[5 ArcTan[1/7] + 4 ArcTan[1/53] + 2 ArcTan[1/4443]] == 1
Tan[6 ArcTan[1/8] + 2 ArcTan[1/57] + ArcTan[1/239]] == 1
Tan[8 ArcTan[1/10] - ArcTan[1/239] - 4 ArcTan[1/515]] == 1
Tan[12 ArcTan[1/18] + 8 ArcTan[1/57] - 5 ArcTan[1/239]] == 1
Tan[16 ArcTan[1/21] + 3 ArcTan[1/239] + 4 ArcTan[3/1042]] == 1
Tan[22 ArcTan[1/28] + 2 ArcTan[1/443] - 5 ArcTan[1/1393] -
10 ArcTan[1/11018]] == 1
Tan[22 ArcTan[1/38] + 17 ArcTan[7/601] + 10 ArcTan[7/8149]] == 1
Tan[44 ArcTan[1/57] + 7 ArcTan[1/239] - 12 ArcTan[1/682] +
24 ArcTan[1/12943]] == 1
Tan[88 ArcTan[1/172] + 51 ArcTan[1/239] + 32 ArcTan[1/682] +
44 ArcTan[1/5357] + 68 ArcTan[1/12943]] == 1
Tan[88 ArcTan[1/172] + 51 ArcTan[1/239] + 32 ArcTan[1/682] +
44 ArcTan[1/5357] + 68 ArcTan[1/12944]] == 1
- Output:
True True True True True True True True True True True True True True True True False
Maxima
trigexpand:true$
is(tan(atan(1/2)+atan(1/3))=1);
is(tan(2*atan(1/3)+atan(1/7))=1);
is(tan(4*atan(1/5)-atan(1/239))=1);
is(tan(5*atan(1/7)+2*atan(3/79))=1);
is(tan(5*atan(29/278)+7*atan(3/79))=1);
is(tan(atan(1/2)+atan(1/5)+atan(1/8))=1);
is(tan(4*atan(1/5)-atan(1/70)+atan(1/99))=1);
is(tan(5*atan(1/7)+4*atan(1/53)+2*atan(1/4443))=1);
is(tan(6*atan(1/8)+2*atan(1/57)+atan(1/239))=1);
is(tan(8*atan(1/10)-atan(1/239)-4*atan(1/515))=1);
is(tan(12*atan(1/18)+8*atan(1/57)-5*atan(1/239))=1);
is(tan(16*atan(1/21)+3*atan(1/239)+4*atan(3/1042))=1);
is(tan(22*atan(1/28)+2*atan(1/443)-5*atan(1/1393)-10*atan(1/11018))=1);
is(tan(22*atan(1/38)+17*atan(7/601)+10*atan(7/8149))=1);
is(tan(44*atan(1/57)+7*atan(1/239)-12*atan(1/682)+24*atan(1/12943))=1);
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12943))=1);
is(tan(88*atan(1/172)+51*atan(1/239)+32*atan(1/682)+44*atan(1/5357)+68*atan(1/12944))=1);
- Output:
(%i2) (%o2) true (%i3) (%o3) true (%i4) (%o4) true (%i5) (%o5) true (%i6) (%o6) true (%i7) (%o7) true (%i8) (%o8) true (%i9) (%o9) true (%i10) (%o10) true (%i11) (%o11) true (%i12) (%o12) true (%i13) (%o13) true (%i14) (%o14) true (%i15) (%o15) true (%i16) (%o16) true (%i17) (%o17) true (%i18) (%o18) false
Nim
The most important part of our program is the formula parser which proceeds to a full syntactical validation. The parser builds an expression which is a sequence of terms, a term being itself composed of a factor and a fraction (the argument to arctan).
import bignum
type
# Description of a term.
Term = object
factor: int # Multiplier (may be negative).
fract: Rat # Argument of arc tangent.
Expression = seq[Term]
# Rational 1.
let One = newRat(1)
####################################################################################################
# Formula parser.
type
# Possible tokens for parsing.
Token = enum tkPi, tkArctan, tkNumber, tkEqual, tkAdd, tkSub,
tkMul, tkDiv, tkLPar, tkRPar, tkError, tkEnd
# Lexer description.
Lexer = object
line: string # The line to parse.
pos: Natural # Current position of lexer.
token: Token # Current token.
value: Natural # Associated value (for numbers).
# Exception raised if an error is found.
SyntaxError = object of CatchableError
#---------------------------------------------------------------------------------------------------
proc initLexer(line: string): Lexer =
## Create and initialize a lexer.
result.line = line
result.pos = 0
#---------------------------------------------------------------------------------------------------
proc parseName(lexer: var Lexer; pos: Natural) =
## Parse a name.
# Build the name.
var pos = pos
var name = ""
while pos < lexer.line.len and (let c = lexer.line[pos]; c) in 'a'..'z':
name.add(c)
inc pos
# Update lexer state.
lexer.token = if name == "arctan": tkArctan
elif name == "pi": tkPi
else: tkError
lexer.pos = pos
#---------------------------------------------------------------------------------------------------
proc parseNumber(lexer: var Lexer; pos: Natural) =
## Parse a number.
# Build the number.
var pos = pos
var value = 0
while pos < lexer.line.len and (let c = lexer.line[pos]; c) in '0'..'9':
value = 10 * value + ord(c) - ord('0')
inc pos
# Update lexer state.
lexer.token = tkNumber
lexer.value = value
lexer.pos = pos
#---------------------------------------------------------------------------------------------------
proc getNextToken(lexer: var Lexer) =
## Find next token.
var pos = lexer.pos
var token: Token
while pos < lexer.line.len and lexer.line[pos] == ' ': inc pos
if pos == lexer.line.len:
# Reached end of string.
lexer.pos = pos
lexer.token = tkEnd
return
# Find token.
case lexer.line[pos]
of '=': token = tkEqual
of '+': token = tkAdd
of '-': token = tkSub
of '*': token = tkMul
of '/': token = tkDiv
of '(': token = tkLPar
of ')': token = tkRPar
of 'a'..'z':
lexer.parseName(pos)
return
of '0'..'9':
lexer.parseNumber(pos)
return
else: token = tkError
# Update lexer state.
lexer.pos = pos + 1
lexer.token = token
#---------------------------------------------------------------------------------------------------
template syntaxError(message: string) =
## Raise a syntax error exception.
raise newException(SyntaxError, message)
#---------------------------------------------------------------------------------------------------
proc parseFraction(lexer: var Lexer): Rat =
## Parse a fraction: number / number.
lexer.getNextToken()
if lexer.token != tkNumber:
syntaxError("number expected.")
let num = lexer.value
lexer.getNextToken()
if lexer.token != tkDiv:
syntaxError("“/” expected.")
lexer.getNextToken()
if lexer.token != tkNumber:
syntaxError("number expected")
if lexer.value == 0:
raise newException(ValueError, "null denominator.")
let den = lexer.value
result = newRat(num, den)
#---------------------------------------------------------------------------------------------------
proc parseTerm(lexer: var Lexer): Term =
## Parse a term: factor * arctan(fraction) or arctan(fraction).
lexer.getNextToken()
# Parse factor.
if lexer.token == tkNumber:
result.factor = lexer.value
lexer.getNextToken
if lexer.token != tkMul:
syntaxError("“*” expected.")
lexer.getNextToken()
else:
result.factor = 1
# Parse arctan.
if lexer.token != tkArctan:
syntaxError("“arctan” expected.")
lexer.getNextToken()
if lexer.token != tkLPar:
syntaxError("“(” expected.")
result.fract = lexer.parseFraction()
lexer.getNextToken()
if lexer.token != tkRPar:
syntaxError("“)” expected.")
#---------------------------------------------------------------------------------------------------
proc parse(line: string): Expression =
## Parse a formula.
var lexer = initLexer(line)
lexer.getNextToken()
if lexer.token != tkPi:
syntaxError("pi symbol expected.")
lexer.getNextToken()
if lexer.token != tkDiv:
syntaxError("'/' expected.")
lexer.getNextToken()
if lexer.token != tkNumber:
syntaxError("number expected.")
if lexer.value != 4:
raise newException(ValueError, "value 4 expected.")
lexer.getNextToken()
if lexer.token != tkEqual:
syntaxError("“=” expected.")
result.add(lexer.parseTerm())
lexer.getNextToken()
# Parse the next terms.
while (let token = lexer.token; token) in {tkAdd, tkSub}:
var term = lexer.parseTerm()
if token == tkSub:
term.factor = -term.factor
result.add(term)
lexer.getNextToken()
if lexer.token != tkEnd:
syntaxError("invalid characters at end of formula.")
####################################################################################################
# Evaluator.
proc tangent(factor: int; fract: Rat): Rat =
## Compute the tangent of "factor * arctan(fract)".
if factor == 1:
return fract
if factor < 0:
return -tangent(-factor, fract)
# Split in two parts.
let n = factor div 2
let a = tangent(n, fract)
let b = tangent(factor - n, fract)
result = (a + b) / (One - a * b)
#---------------------------------------------------------------------------------------------------
proc tangent(expr: Expression): Rat =
## Compute the tangent of a sum of terms.
if expr.len == 1:
result = tangent(expr[0].factor, expr[0].fract)
else:
# Split in two parts.
let a = tangent(expr[0..<(expr.len div 2)])
let b = tangent(expr[(expr.len div 2)..^1])
result = (a + b) / (One - a * b)
#———————————————————————————————————————————————————————————————————————————————————————————————————
when isMainModule:
const Formulas = [
"pi/4 = arctan(1/2) + arctan(1/3)",
"pi/4 = 2*arctan(1/3) + arctan(1/7)",
"pi/4 = 4*arctan(1/5) - arctan(1/239)",
"pi/4 = 5*arctan(1/7) + 2*arctan(3/79)",
"pi/4 = 5*arctan(29/278) + 7*arctan(3/79)",
"pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)",
"pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)",
"pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)",
"pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)",
"pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)",
"pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)",
"pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)",
"pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)",
"pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)",
"pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)",
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)",
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)"]
for formula in Formulas:
let expr = formula.parse()
let value = tangent(expr)
if value == 1:
echo "True: ", formula
else:
echo "False: ", formula
echo "Tangent of the right expression is about ", value.toFloat
- Output:
True: pi/4 = arctan(1/2) + arctan(1/3) True: pi/4 = 2*arctan(1/3) + arctan(1/7) True: pi/4 = 4*arctan(1/5) - arctan(1/239) True: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) True: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) True: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) True: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) True: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) True: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) True: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) True: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) True: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) True: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) True: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) True: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) True: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) False: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) Tangent of the right expression is about 0.9999991882257444
OCaml
open Num;; (* use exact rationals for results *)
let tadd p q = (p +/ q) // ((Int 1) -/ (p */ q)) in
(* tan(n*arctan(a/b)) *)
let rec tan_expr (n,a,b) =
if n = 1 then (Int a)//(Int b) else
if n = -1 then (Int (-a))//(Int b) else
let m = n/2 in
let tm = tan_expr (m,a,b) in
let m2 = tadd tm tm and k = n-m-m in
if k = 0 then m2 else tadd (tan_expr (k,a,b)) m2 in
let verify (k, tlist) =
Printf.printf "Testing: pi/%d = " k;
let t_str = List.map (fun (x,y,z) -> Printf.sprintf "%d*atan(%d/%d)" x y z) tlist in
print_endline (String.concat " + " t_str);
let ans_terms = List.map tan_expr tlist in
let answer = List.fold_left tadd (Int 0) ans_terms in
Printf.printf " tan(RHS) is %s\n" (if answer = (Int 1) then "one" else "not one") in
(* example: prog 4 5 29 278 7 3 79 represents pi/4 = 5*atan(29/278) + 7*atan(3/79) *)
let args = Sys.argv in
let nargs = Array.length args in
let v k = int_of_string args.(k) in
let rec triples n =
if n+2 > nargs-1 then []
else (v n, v (n+1), v (n+2)) :: triples (n+3) in
if nargs > 4 then
let dat = (v 1, triples 2) in
verify dat
else
List.iter verify [
(4,[(1,1,2);(1,1,3)]);
(4,[(2,1,3);(1,1,7)]);
(4,[(4,1,5);(-1,1,239)]);
(4,[(5,1,7);(2,3,79)]);
(4,[(5,29,278);(7,3,79)]);
(4,[(1,1,2);(1,1,5);(1,1,8)]);
(4,[(4,1,5);(-1,1,70);(1,1,99)]);
(4,[(5,1,7);(4,1,53);(2,1,4443)]);
(4,[(6,1,8);(2,1,57);(1,1,239)]);
(4,[(8,1,10);(-1,1,239);(-4,1,515)]);
(4,[(12,1,18);(8,1,57);(-5,1,239)]);
(4,[(16,1,21);(3,1,239);(4,3,1042)]);
(4,[(22,1,28);(2,1,443);(-5,1,1393);(-10,1,11018)]);
(4,[(22,1,38);(17,7,601);(10,7,8149)]);
(4,[(44,1,57);(7,1,239);(-12,1,682);(24,1,12943)]);
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12943)]);
(4,[(88,1,172);(51,1,239);(32,1,682);(44,1,5357);(68,1,12944)])
]
Compile with
ocamlopt -o verify_machin.opt nums.cmxa verify_machin.ml
or run with
ocaml nums.cma verify_machin.ml
- Output:
Testing: pi/4 = 1*atan(1/2) + 1*atan(1/3) tan(RHS) is one Testing: pi/4 = 2*atan(1/3) + 1*atan(1/7) tan(RHS) is one Testing: pi/4 = 4*atan(1/5) + -1*atan(1/239) tan(RHS) is one Testing: pi/4 = 5*atan(1/7) + 2*atan(3/79) tan(RHS) is one Testing: pi/4 = 5*atan(29/278) + 7*atan(3/79) tan(RHS) is one Testing: pi/4 = 1*atan(1/2) + 1*atan(1/5) + 1*atan(1/8) tan(RHS) is one Testing: pi/4 = 4*atan(1/5) + -1*atan(1/70) + 1*atan(1/99) tan(RHS) is one Testing: pi/4 = 5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443) tan(RHS) is one Testing: pi/4 = 6*atan(1/8) + 2*atan(1/57) + 1*atan(1/239) tan(RHS) is one Testing: pi/4 = 8*atan(1/10) + -1*atan(1/239) + -4*atan(1/515) tan(RHS) is one Testing: pi/4 = 12*atan(1/18) + 8*atan(1/57) + -5*atan(1/239) tan(RHS) is one Testing: pi/4 = 16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042) tan(RHS) is one Testing: pi/4 = 22*atan(1/28) + 2*atan(1/443) + -5*atan(1/1393) + -10*atan(1/11018) tan(RHS) is one Testing: pi/4 = 22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149) tan(RHS) is one Testing: pi/4 = 44*atan(1/57) + 7*atan(1/239) + -12*atan(1/682) + 24*atan(1/12943) tan(RHS) is one Testing: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12943) tan(RHS) is one Testing: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944) tan(RHS) is not one
ooRexx
/*REXX ----------------------------------------------------------------
* 09.04.2014 Walter Pachl the REXX solution adapted for ooRexx
* which provides a function package rxMath
*--------------------------------------------------------------------*/
Numeric Digits 16
Numeric Fuzz 3; pi=rxCalcpi(); a.=''
a.1 = 'pi/4 = rxCalcarctan(1/2,16,'R') + rxCalcarctan(1/3,16,'R')'
a.2 = 'pi/4 = 2*rxCalcarctan(1/3,16,'R') + rxCalcarctan(1/7,16,'R')'
a.3 = 'pi/4 = 4*rxCalcarctan(1/5,16,'R') - rxCalcarctan(1/239,16,'R')'
a.4 = 'pi/4 = 5*rxCalcarctan(1/7,16,'R') + 2*rxCalcarctan(3/79,16,'R')'
a.5 = 'pi/4 = 5*rxCalcarctan(29/278,16,'R') + 7*rxCalcarctan(3/79,16,'R')'
a.6 = 'pi/4 = rxCalcarctan(1/2,16,'R') + rxCalcarctan(1/5,16,'R') + rxCalcarctan(1/8,16,'R')'
a.7 = 'pi/4 = 4*rxCalcarctan(1/5,16,'R') - rxCalcarctan(1/70,16,'R') + rxCalcarctan(1/99,16,'R')'
a.8 = 'pi/4 = 5*rxCalcarctan(1/7,16,'R') + 4*rxCalcarctan(1/53,16,'R') + 2*rxCalcarctan(1/4443,16,'R')'
a.9 = 'pi/4 = 6*rxCalcarctan(1/8,16,'R') + 2*rxCalcarctan(1/57,16,'R') + rxCalcarctan(1/239,16,'R')'
a.10 = 'pi/4 = 8*rxCalcarctan(1/10,16,'R') - rxCalcarctan(1/239,16,'R') - 4*rxCalcarctan(1/515,16,'R')'
a.11 = 'pi/4 = 12*rxCalcarctan(1/18,16,'R') + 8*rxCalcarctan(1/57,16,'R') - 5*rxCalcarctan(1/239,16,'R')'
a.12 = 'pi/4 = 16*rxCalcarctan(1/21,16,'R') + 3*rxCalcarctan(1/239,16,'R') + 4*rxCalcarctan(3/1042,16,'R')'
a.13 = 'pi/4 = 22*rxCalcarctan(1/28,16,'R') + 2*rxCalcarctan(1/443,16,'R') - 5*rxCalcarctan(1/1393,16,'R') - 10*rxCalcarctan(1/11018,16,'R')'
a.14 = 'pi/4 = 22*rxCalcarctan(1/38,16,'R') + 17*rxCalcarctan(7/601,16,'R') + 10*rxCalcarctan(7/8149,16,'R')'
a.15 = 'pi/4 = 44*rxCalcarctan(1/57,16,'R') + 7*rxCalcarctan(1/239,16,'R') - 12*rxCalcarctan(1/682,16,'R') + 24*rxCalcarctan(1/12943,16,'R')'
a.16 = 'pi/4 = 88*rxCalcarctan(1/172,16,'R') + 51*rxCalcarctan(1/239,16,'R') + 32*rxCalcarctan(1/682,16,'R') + 44*rxCalcarctan(1/5357,16,'R') + 68*rxCalcarctan(1/12943,16,'R')'
a.17 = 'pi/4 = 88*rxCalcarctan(1/172,16,'R') + 51*rxCalcarctan(1/239,16,'R') + 32*rxCalcarctan(1/682,16,'R') + 44*rxCalcarctan(1/5357,16,'R') + 68*rxCalcarctan(1/12944,16,'R')'
do j=1 while a.j\=='' /*evaluate each of the formulas. */
interpret 'answer=' "(" a.j ")" /*the heavy lifting.*/
say right(word('bad OK',answer+1),3)": " space(a.j,0)
end /*j*/ /* [?] show OK | bad, formula. */
::requires rxmath library
- Output:
OK: pi/4=rxCalcarctan(1/2,16,R)+rxCalcarctan(1/3,16,R) OK: pi/4=2*rxCalcarctan(1/3,16,R)+rxCalcarctan(1/7,16,R) OK: pi/4=4*rxCalcarctan(1/5,16,R)-rxCalcarctan(1/239,16,R) OK: pi/4=5*rxCalcarctan(1/7,16,R)+2*rxCalcarctan(3/79,16,R) OK: pi/4=5*rxCalcarctan(29/278,16,R)+7*rxCalcarctan(3/79,16,R) OK: pi/4=rxCalcarctan(1/2,16,R)+rxCalcarctan(1/5,16,R)+rxCalcarctan(1/8,16,R) OK: pi/4=4*rxCalcarctan(1/5,16,R)-rxCalcarctan(1/70,16,R)+rxCalcarctan(1/99,16,R) OK: pi/4=5*rxCalcarctan(1/7,16,R)+4*rxCalcarctan(1/53,16,R)+2*rxCalcarctan(1/4443,16,R) OK: pi/4=6*rxCalcarctan(1/8,16,R)+2*rxCalcarctan(1/57,16,R)+rxCalcarctan(1/239,16,R) OK: pi/4=8*rxCalcarctan(1/10,16,R)-rxCalcarctan(1/239,16,R)-4*rxCalcarctan(1/515,16,R) OK: pi/4=12*rxCalcarctan(1/18,16,R)+8*rxCalcarctan(1/57,16,R)-5*rxCalcarctan(1/239,16,R) OK: pi/4=16*rxCalcarctan(1/21,16,R)+3*rxCalcarctan(1/239,16,R)+4*rxCalcarctan(3/1042,16,R) OK: pi/4=22*rxCalcarctan(1/28,16,R)+2*rxCalcarctan(1/443,16,R)-5*rxCalcarctan(1/1393,16,R)-10*rxCalcarctan(1/11018,16,R) OK: pi/4=22*rxCalcarctan(1/38,16,R)+17*rxCalcarctan(7/601,16,R)+10*rxCalcarctan(7/8149,16,R) OK: pi/4=44*rxCalcarctan(1/57,16,R)+7*rxCalcarctan(1/239,16,R)-12*rxCalcarctan(1/682,16,R)+24*rxCalcarctan(1/12943,16,R) OK: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12943,16,R) bad: pi/4=88*rxCalcarctan(1/172,16,R)+51*rxCalcarctan(1/239,16,R)+32*rxCalcarctan(1/682,16,R)+44*rxCalcarctan(1/5357,16,R)+68*rxCalcarctan(1/12944,16,R)
PARI/GP
tanEval(coef, f)={
if (coef <= 1, return(if(coef<1,-tanEval(-coef, f),f)));
my(a=tanEval(coef\2, f), b=tanEval(coef-coef\2, f));
(a + b)/(1 - a*b)
};
tans(xs)={
if (#xs == 1, return(tanEval(xs[1][1], xs[1][2])));
my(a=tans(xs[1..#xs\2]),b=tans(xs[#xs\2+1..#xs]));
(a + b)/(1 - a*b)
};
test(v)={
my(t=tans(v));
if(t==1,print("OK"),print("Error: "v))
};
test([[1,1/2],[1,1/3]]);
test([[2,1/3],[1,1/7]]);
test([[4,1/5],[-1,1/239]]);
test([[5,1/7],[2,3/79]]);
test([[5,29/278],[7,3/79]]);
test([[1,1/2],[1,1/5],[1,1/8]]);
test([[4,1/5],[-1,1/70],[1,1/99]]);
test([[5,1/7],[4,1/53],[2,1/4443]]);
test([[6,1/8],[2,1/57],[1,1/239]]);
test([[8,1/10],[-1,1/239],[-4,1/515]]);
test([[12,1/18],[8,1/57],[-5,1/239]]);
test([[16,1/21],[3,1/239],[4,3/1042]]);
test([[22,1/28],[2,1/443],[-5,1/1393],[-10,1/11018]]);
test([[22,1/38],[17,7/601],[10,7/8149]]);
test([[44,1/57],[7,1/239],[-12,1/682],[24,1/12943]]);
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12943]]);
test([[88,1/172],[51,1/239],[32,1/682],[44,1/5357],[68,1/12944]]);
- Output:
OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK Error: [[88, 1/172], [51, 1/239], [32, 1/682], [44, 1/5357], [68, 1/12944]]
Perl
use Math::BigRat try=>"GMP";
sub taneval {
my($coef,$f) = @_;
$f = Math::BigRat->new($f) unless ref($f);
return 0 if $coef == 0;
return $f if $coef == 1;
return -taneval(-$coef, $f) if $coef < 0;
my($a,$b) = ( taneval($coef>>1, $f), taneval($coef-($coef>>1),$f) );
($a+$b)/(1-$a*$b);
}
sub tans {
my @xs=@_;
return taneval(@{$xs[0]}) if scalar(@xs)==1;
my($a,$b) = ( tans(@xs[0..($#xs>>1)]), tans(@xs[($#xs>>1)+1..$#xs]) );
($a+$b)/(1-$a*$b);
}
sub test {
printf "%5s (%s)\n", (tans(@_)==1)?"OK":"Error", join(" ",map{"[@$_]"} @_);
}
test([1,'1/2'], [1,'1/3']);
test([2,'1/3'], [1,'1/7']);
test([4,'1/5'], [-1,'1/239']);
test([5,'1/7'],[2,'3/79']);
test([5,'29/278'],[7,'3/79']);
test([1,'1/2'],[1,'1/5'],[1,'1/8']);
test([4,'1/5'],[-1,'1/70'],[1,'1/99']);
test([5,'1/7'],[4,'1/53'],[2,'1/4443']);
test([6,'1/8'],[2,'1/57'],[1,'1/239']);
test([8,'1/10'],[-1,'1/239'],[-4,'1/515']);
test([12,'1/18'],[8,'1/57'],[-5,'1/239']);
test([16,'1/21'],[3,'1/239'],[4,'3/1042']);
test([22,'1/28'],[2,'1/443'],[-5,'1/1393'],[-10,'1/11018']);
test([22,'1/38'],[17,'7/601'],[10,'7/8149']);
test([44,'1/57'],[7,'1/239'],[-12,'1/682'],[24,'1/12943']);
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12943']);
test([88,'1/172'],[51,'1/239'],[32,'1/682'],[44,'1/5357'],[68,'1/12944']);
- Output:
OK ([1 1/2] [1 1/3]) OK ([2 1/3] [1 1/7]) OK ([4 1/5] [-1 1/239]) OK ([5 1/7] [2 3/79]) OK ([5 29/278] [7 3/79]) OK ([1 1/2] [1 1/5] [1 1/8]) OK ([4 1/5] [-1 1/70] [1 1/99]) OK ([5 1/7] [4 1/53] [2 1/4443]) OK ([6 1/8] [2 1/57] [1 1/239]) OK ([8 1/10] [-1 1/239] [-4 1/515]) OK ([12 1/18] [8 1/57] [-5 1/239]) OK ([16 1/21] [3 1/239] [4 3/1042]) OK ([22 1/28] [2 1/443] [-5 1/1393] [-10 1/11018]) OK ([22 1/38] [17 7/601] [10 7/8149]) OK ([44 1/57] [7 1/239] [-12 1/682] [24 1/12943]) OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12944])
Phix
Naive version
Rather than test tan(a) for 1.0, test whether the sprint of it, which is rounded to 10 significant digits, is "1.0" or "1".
At the end we deliberately show a test case that should and does fail.
with javascript_semantics procedure test(atom a) if -3*PI/4 >= a then ?9/0 end if if 5*PI/4 <= a then ?9/0 end if string s = sprint(tan(a)) ?s -- or test for "1.0"/"1", but not 1.0 end procedure test( arctan(1 / 2) + arctan(1 / 3)) test( 2*arctan(1 / 3) + arctan(1 / 7)) test( 4*arctan(1 / 5) - arctan(1 / 239)) test( 5*arctan(1 / 7) + 2*arctan(3 / 79)) test( 5*arctan(29/ 278) + 7*arctan(3 / 79)) test( arctan(1 / 2) + arctan(1 / 5) + arctan(1 / 8)) test( 4*arctan(1 / 5) - arctan(1 / 70) + arctan(1 / 99)) test( 5*arctan(1 / 7) + 4*arctan(1 / 53) + 2*arctan(1 / 4443)) test( 6*arctan(1 / 8) + 2*arctan(1 / 57) + arctan(1 / 239)) test( 8*arctan(1 / 10) - arctan(1 / 239) - 4*arctan(1 / 515)) test(12*arctan(1 / 18) + 8*arctan(1 / 57) - 5*arctan(1 / 239)) test(16*arctan(1 / 21) + 3*arctan(1 / 239) + 4*arctan(3 / 1042)) test(22*arctan(1 / 28) + 2*arctan(1 / 443) - 5*arctan(1 / 1393) - 10*arctan(1 / 11018)) test(22*arctan(1 / 38) + 17*arctan(7 / 601) +10*arctan(7 / 8149)) test(44*arctan(1 / 57) + 7*arctan(1 / 239) -12*arctan(1 / 682) + 24*arctan(1 / 12943)) test(88*arctan(1 / 172) + 51*arctan(1 / 239) +32*arctan(1 / 682) + 44*arctan(1 / 5357) + 68*arctan(1 / 12943)) ?"===" test(88*arctan(1 / 172) + 51*arctan(1 / 239) + 32*arctan(1 / 682) + 44*arctan(1 / 5357) + 68*arctan(1 / 12944))
- Output:
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 "===" 0.9999991882
Using proper fractions
with javascript_semantics include mpfr.e function tans(sequence x) sequence args = repeat(0,length(x)) mpq {a,b,aab,mab} = mpq_inits(4) integer h if length(x)=1 then {integer m, mpq f} = x[1] if m=1 then mpq_set(a,f) return a elsif m<0 then f = tans({{-m,f}}) mpq_neg(f,f) return f end if h = floor(m/2) a = tans({{h,f}}) b = tans({{m-h,f}}) else h = floor(length(x)/2) a = tans(x[1..h]) b = tans(x[h+1..$]) end if mpq_mul(mab,a,b) mpq_add(aab,a,b) mpq_set_si(b,1) mpq_sub(b,b,mab) mpq_div(a,aab,b) {b,aab,mab} = mpq_free({b,aab,mab}) return a end function function parse(string formula) -- obviously the error handling here is a bit brutal... formula = substitute(formula," ","") -- strip spaces if formula[1..5]!="pi/4=" then ?9/0 end if formula = formula[6..$] sequence res = {}, r while length(formula) do integer sgn = +1, m, n, d switch formula[1] do case '-': sgn = -1; fallthrough case '+': formula = formula[2..$] end switch if formula[1]='a' then m = sgn else r = scanf(formula,"%d*%s") if length(r)!=1 then ?9/0 end if {m,formula} = r[1] m *= sgn end if r = scanf(formula,"arctan(%d/%d)%s") if length(r)!=1 then ?9/0 end if {n,d,formula} = r[1] res = append(res,{m,mpq_init_set_si(n,d)}) end while return res end function procedure test(string formula) mpq f = tans(parse(formula)) if mpq_cmp_si(f,1)=0 then printf(1,"OK: %s\n",{formula}) else printf(1,"ERROR: %s\n",{formula}) mpz {n,d} = mpz_inits(2) mpq_get_num(n,f) mpq_get_den(d,f) printf(1," %s\n\\ %s\n",{shorten(mpz_get_str(n)), shorten(mpz_get_str(d))}) end if end procedure constant formulae = {"pi/4 = arctan(1/2) + arctan(1/3)", "pi/4 = 2*arctan(1/3) + arctan(1/7)", "pi/4 = 4*arctan(1/5) - arctan(1/239)", "pi/4 = 5*arctan(1/7) + 2*arctan(3/79)", "pi/4 = 5*arctan(29/278) + 7*arctan(3/79)", "pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)", "pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)", "pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)", "pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)", "pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)", "pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)", "pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)", "pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)", "pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)", "pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)", "pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)", "pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)"} for i=1 to length(formulae) do test(formulae[i]) end for
- Output:
As above, the last case should and does fail.
OK: pi/4 = arctan(1/2) + arctan(1/3) OK: pi/4 = 2*arctan(1/3) + arctan(1/7) OK: pi/4 = 4*arctan(1/5) - arctan(1/239) OK: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) OK: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) OK: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) OK: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) OK: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) OK: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) OK: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) OK: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) OK: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) OK: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) OK: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) OK: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944) 10092880180009440509...99840402353522108223 (550 digits) \ 10092888373156385834...60371264507984339711 (550 digits)
Python
This example parses the original equations to form an intermediate representation then does the checks.
Function tans and tanEval are translations of the Haskell functions of the same names.
import re
from fractions import Fraction
from pprint import pprint as pp
equationtext = '''\
pi/4 = arctan(1/2) + arctan(1/3)
pi/4 = 2*arctan(1/3) + arctan(1/7)
pi/4 = 4*arctan(1/5) - arctan(1/239)
pi/4 = 5*arctan(1/7) + 2*arctan(3/79)
pi/4 = 5*arctan(29/278) + 7*arctan(3/79)
pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)
pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)
pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)
pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)
pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)
pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)
pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)
pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)
pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)
pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
'''
def parse_eqn(equationtext=equationtext):
eqn_re = re.compile(r"""(?mx)
(?P<lhs> ^ \s* pi/4 \s* = \s*)? # LHS of equation
(?: # RHS
\s* (?P<sign> [+-])? \s*
(?: (?P<mult> \d+) \s* \*)?
\s* arctan\( (?P<numer> \d+) / (?P<denom> \d+)
)""")
found = eqn_re.findall(equationtext)
machins, part = [], []
for lhs, sign, mult, numer, denom in eqn_re.findall(equationtext):
if lhs and part:
machins.append(part)
part = []
part.append( ( (-1 if sign == '-' else 1) * ( int(mult) if mult else 1),
Fraction(int(numer), (int(denom) if denom else 1)) ) )
machins.append(part)
return machins
def tans(xs):
xslen = len(xs)
if xslen == 1:
return tanEval(*xs[0])
aa, bb = xs[:xslen//2], xs[xslen//2:]
a, b = tans(aa), tans(bb)
return (a + b) / (1 - a * b)
def tanEval(coef, f):
if coef == 1:
return f
if coef < 0:
return -tanEval(-coef, f)
ca = coef // 2
cb = coef - ca
a, b = tanEval(ca, f), tanEval(cb, f)
return (a + b) / (1 - a * b)
if __name__ == '__main__':
machins = parse_eqn()
#pp(machins, width=160)
for machin, eqn in zip(machins, equationtext.split('\n')):
ans = tans(machin)
print('%5s: %s' % ( ('OK' if ans == 1 else 'ERROR'), eqn))
- Output:
OK: pi/4 = arctan(1/2) + arctan(1/3) OK: pi/4 = 2*arctan(1/3) + arctan(1/7) OK: pi/4 = 4*arctan(1/5) - arctan(1/239) OK: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) OK: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) OK: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) OK: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) OK: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) OK: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) OK: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) OK: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) OK: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) OK: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) OK: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) OK: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
Note: the Kodos tool was used in developing the regular expression.
R
#lang R
library(Rmpfr)
prec <- 1000 # precision in bits
`%:%` <- function(e1, e2) '/'(mpfr(e1, prec), mpfr(e2, prec)) # operator %:% for high precision division
# function for checking identity of tan of expression and 1, making use of high precision division operator %:%
tanident_1 <- function(x) identical(round(tan(eval(parse(text = gsub("/", "%:%", deparse(substitute(x)))))), (prec/10)), mpfr(1, prec))
- Output:
tanident_1( 1*atan(1/2) + 1*atan(1/3) )
## [1] TRUE
tanident_1( 2*atan(1/3) + 1*atan(1/7))
## [1] TRUE
tanident_1( 4*atan(1/5) + -1*atan(1/239))
## [1] TRUE
tanident_1( 5*atan(1/7) + 2*atan(3/79))
## [1] TRUE
tanident_1( 5*atan(29/278) + 7*atan(3/79))
## [1] TRUE
tanident_1( 1*atan(1/2) + 1*atan(1/5) + 1*atan(1/8) )
## [1] TRUE
tanident_1( 4*atan(1/5) + -1*atan(1/70) + 1*atan(1/99) )
## [1] TRUE
tanident_1( 5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443))
## [1] TRUE
tanident_1( 6*atan(1/8) + 2*atan(1/57) + 1*atan(1/239))
## [1] TRUE
tanident_1( 8*atan(1/10) + -1*atan(1/239) + -4*atan(1/515))
## [1] TRUE
tanident_1(12*atan(1/18) + 8*atan(1/57) + -5*atan(1/239))
## [1] TRUE
tanident_1(16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042))
## [1] TRUE
tanident_1(22*atan(1/28) + 2*atan(1/443) + -5*atan(1/1393) + -10*atan(1/11018))
## [1] TRUE
tanident_1(22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149))
## [1] TRUE
tanident_1(44*atan(1/57) + 7*atan(1/239) + -12*atan(1/682) + 24*atan(1/12943))
## [1] TRUE
tanident_1(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12943))
## [1] TRUE
tanident_1(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944))
## [1] FALSE
Racket
#lang racket
(define (reduce e)
(match e
[(? number? a) a]
[(list '+ (? number? a) (? number? b)) (+ a b)]
[(list '- (? number? a) (? number? b)) (- a b)]
[(list '- (? number? a)) (- a)]
[(list '* (? number? a) (? number? b)) (* a b)]
[(list '/ (? number? a) (? number? b)) (/ a b)]
[(list '+ a b) (reduce `(+ ,(reduce a) ,(reduce b)))]
[(list '- a b) (reduce `(- ,(reduce a) ,(reduce b)))]
[(list '- a) (reduce `(- ,(reduce a)))]
[(list '* a b) (reduce `(* ,(reduce a) ,(reduce b)))]
[(list '/ a b) (reduce `(/ ,(reduce a) ,(reduce b)))]
[(list 'tan (list 'arctan a)) (reduce a)]
[(list 'tan (list '- a)) (reduce `(- ,(reduce `(tan ,a))))]
[(list 'tan (list '+ a b)) (reduce `(/ (+ (tan ,a) (tan ,b))
(- 1 (* (tan ,a) (tan ,b)))))]
[(list 'tan (list '+ a b c ...)) (reduce `(tan (+ ,a (+ ,b ,@c))))]
[(list 'tan (list '- a b)) (reduce `(/ (+ (tan ,a) (tan (- ,b)))
(- 1 (* (tan ,a) (tan (- ,b))))))]
[(list 'tan (list '* 1 a)) (reduce `(tan ,a))]
[(list 'tan (list '* (? number? n) a))
(cond [(< n 0) (reduce `(- (tan (* ,(- n) ,a))))]
[(= n 0) 0]
[(even? n) (reduce `(tan (+ (* ,(/ n 2) ,a) (* ,(/ n 2) ,a))))]
[else (reduce `(tan (+ ,a (* ,(- n 1) ,a))))])]))
(define correct-formulas
'((tan (+ (arctan 1/2) (arctan 1/3)))
(tan (+ (* 2 (arctan 1/3)) (arctan 1/7)))
(tan (- (* 4 (arctan 1/5)) (arctan 1/239)))
(tan (+ (* 5 (arctan 1/7)) (* 2 (arctan 3/79))))
(tan (+ (* 5 (arctan 29/278)) (* 7 (arctan 3/79))))
(tan (+ (arctan 1/2) (arctan 1/5) (arctan 1/8)))
(tan (+ (* 4 (arctan 1/5)) (* -1 (arctan 1/70)) (arctan 1/99)))
(tan (+ (* 5 (arctan 1/7)) (* 4 (arctan 1/53)) (* 2 (arctan 1/4443))))
(tan (+ (* 6 (arctan 1/8)) (* 2 (arctan 1/57)) (arctan 1/239)))
(tan (+ (* 8 (arctan 1/10)) (* -1 (arctan 1/239)) (* -4 (arctan 1/515))))
(tan (+ (* 12 (arctan 1/18)) (* 8 (arctan 1/57)) (* -5 (arctan 1/239))))
(tan (+ (* 16 (arctan 1/21)) (* 3 (arctan 1/239)) (* 4 (arctan 3/1042))))
(tan (+ (* 22 (arctan 1/28)) (* 2 (arctan 1/443)) (* -5 (arctan 1/1393)) (* -10 (arctan 1/11018))))
(tan (+ (* 22 (arctan 1/38)) (* 17 (arctan 7/601)) (* 10 (arctan 7/8149))))
(tan (+ (* 44 (arctan 1/57)) (* 7 (arctan 1/239)) (* -12 (arctan 1/682)) (* 24 (arctan 1/12943))))
(tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12943))))))
(define wrong-formula
'(tan (+ (* 88 (arctan 1/172)) (* 51 (arctan 1/239)) (* 32 (arctan 1/682))
(* 44 (arctan 1/5357)) (* 68 (arctan 1/12944)))))
(displayln "Do all correct formulas reduce to 1?")
(for/and ([f correct-formulas]) (= 1 (reduce f)))
(displayln "The incorrect formula reduces to:")
(reduce wrong-formula)
Output:
Do all correct formulas reduce to 1?
#t
The incorrect formula reduces to:
1009288018000944050967896710431587186456256928584351786643498522649995492271475761189348270710224618853590682465929080006511691833816436374107451368838065354726517908250456341991684635768915704374493675498637876700129004484434187627909285979251682006538817341793224963346197503893270875008524149334251672855130857035205217929335932890740051319216343365800342290782260673215928499123722781078448297609548233999010983373327601187505623621602789012550584784738082074783523787011976757247516095289966708782862528690942242793667539020699840402353522108223/1009288837315638583415701528780402795721935641614456853534313491853293025565940011104051964874275710024625850092154664245109626053906509780125743180758231049920425664246286578958307532545458843067352531217230461290763258378749459637420702619029075083089762088232401888676895047947363883809724322868121990870409574061477638203859217672620508200713073485398199091153535700094640095900731630771349477187594074169815106104524371099618096164871416282464532355211521113449237814080332335526420331468258917484010722587072087349909684004660371264507984339711
Raku
(formerly Perl 6)
The coercion to FatRat provides for exact computation for all input.
sub taneval ($coef, $f) {
return 0 if $coef == 0;
return $f if $coef == 1;
return -taneval(-$coef, $f) if $coef < 0;
my $a = taneval($coef+>1, $f);
my $b = taneval($coef - $coef+>1, $f);
($a+$b)/(1-$a*$b);
}
sub tans (@xs) {
return taneval(@xs[0;0], @xs[0;1].FatRat) if @xs == 1;
my $a = tans(@xs[0 .. (-1+@xs+>1)]);
my $b = tans(@xs[(-1+@xs+>1)+1 .. -1+@xs]);
($a+$b)/(1-$a*$b);
}
sub verify (@eqn) {
printf "%5s (%s)\n", (tans(@eqn) == 1) ?? "OK" !! "Error",
(map { "[{.[0]} {.[1].nude.join('/')}]" }, @eqn).join(' ');
}
verify($_) for
([[1,1/2], [1,1/3]],
[[2,1/3], [1,1/7]],
[[4,1/5], [-1,1/239]],
[[5,1/7], [2,3/79]],
[[5,29/278], [7,3/79]],
[[1,1/2], [1,1/5], [1,1/8]],
[[4,1/5], [-1,1/70], [1,1/99]],
[[5,1/7], [4,1/53], [2,1/4443]],
[[6,1/8], [2,1/57], [1,1/239]],
[[8,1/10], [-1,1/239], [-4,1/515]],
[[12,1/18], [8,1/57], [-5,1/239]],
[[16,1/21], [3,1/239], [4,3/1042]],
[[22,1/28], [2,1/443], [-5,1/1393], [-10,1/11018]],
[[22,1/38], [17,7/601], [10,7/8149]],
[[44,1/57], [7,1/239], [-12,1/682], [24,1/12943]],
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/12943]],
[[88,1/172], [51,1/239], [32,1/682], [44,1/5357], [68,1/21944]]
);
- Output:
OK ([1 1/2] [1 1/3]) OK ([2 1/3] [1 1/7]) OK ([4 1/5] [-1 1/239]) OK ([5 1/7] [2 3/79]) OK ([5 29/278] [7 3/79]) OK ([1 1/2] [1 1/5] [1 1/8]) OK ([4 1/5] [-1 1/70] [1 1/99]) OK ([5 1/7] [4 1/53] [2 1/4443]) OK ([6 1/8] [2 1/57] [1 1/239]) OK ([8 1/10] [-1 1/239] [-4 1/515]) OK ([12 1/18] [8 1/57] [-5 1/239]) OK ([16 1/21] [3 1/239] [4 3/1042]) OK ([22 1/28] [2 1/443] [-5 1/1393] [-10 1/11018]) OK ([22 1/38] [17 7/601] [10 7/8149]) OK ([44 1/57] [7 1/239] [-12 1/682] [24 1/12943]) OK ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/12943]) Error ([88 1/172] [51 1/239] [32 1/682] [44 1/5357] [68 1/21944])
REXX
Note: REXX doesn't have many high─order math functions, so a few of them are included here.
Noticed: the test arguments specified for this Rosetta Code task need only nine decimal digits for verification, eight decimal digits is not enough to catch the "bad" equation. With this in mind, the REXX's decimal digit precision was increased to the number of decimal digits specified for the variable pi (which, for these cases, is a bit of overkill, but the difference in execution times were barely noticeable).
An extra formula was added to stress test the near exactness of a value.
/*REXX program evaluates some Machin─like formulas and verifies their veracity. */
@.=; pi= pi(); numeric digits( length(pi) ) - length(.); numeric fuzz 3
say center(' computing with ' digits() " decimal digits ", 110, '═')
@.1 = 'pi/4 = atan(1/2) + atan(1/3)'
@.2 = 'pi/4 = 2*atan(1/3) + atan(1/7)'
@.3 = 'pi/4 = 4*atan(1/5) - atan(1/239)'
@.4 = 'pi/4 = 5*atan(1/7) + 2*atan(3/79)'
@.5 = 'pi/4 = 5*atan(29/278) + 7*atan(3/79)'
@.6 = 'pi/4 = atan(1/2) + atan(1/5) + atan(1/8)'
@.7 = 'pi/4 = 4*atan(1/5) - atan(1/70) + atan(1/99)'
@.8 = 'pi/4 = 5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443)'
@.9 = 'pi/4 = 6*atan(1/8) + 2*atan(1/57) + atan(1/239)'
@.10= 'pi/4 = 8*atan(1/10) - atan(1/239) - 4*atan(1/515)'
@.11= 'pi/4 = 12*atan(1/18) + 8*atan(1/57) - 5*atan(1/239)'
@.12= 'pi/4 = 16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042)'
@.13= 'pi/4 = 22*atan(1/28) + 2*atan(1/443) - 5*atan(1/1393) - 10*atan(1/11018)'
@.14= 'pi/4 = 22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149)'
@.15= 'pi/4 = 44*atan(1/57) + 7*atan(1/239) - 12*atan(1/682) + 24*atan(1/12943)'
@.16= 'pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12943)'
@.17= 'pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12944)'
@.18= 'pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 67.9999999994*atan(1/12943)'
do j=1 while @.j\=='' /*evaluate each "Machin─like" formulas.*/
interpret 'answer=' @.j /*where REXX does the heavy lifting. */
say right( word( 'bad OK', answer + 1), 3)": " @.j
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
pi: return 3.141592653589793238462643383279502884197169399375105820974944592307816406286
Acos: procedure; parse arg x; return pi() * .5 - Asin(x)
Atan: procedure; arg x; if abs(x)=1 then return pi()/4*sign(x); return Asin(x/sqrt(1+x*x))
/*──────────────────────────────────────────────────────────────────────────────────────*/
Asin: procedure; parse arg x 1 z 1 o 1 p; a=abs(x); aa=a*a
if a>=sqrt(2)*.5 then return sign(x) * Acos( sqrt(1 - aa) )
do j=2 by 2 until p=z; p=z; o=o*aa*(j-1)/j; z=z+o/(j+1); end /*j*/; return z
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); m.=9; h=d+6; numeric form
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g
- output when using the internal default input:
════════════════════════════════════ computing with 76 decimal digits ════════════════════════════════════ OK: pi/4 = atan(1/2) + atan(1/3) OK: pi/4 = 2*atan(1/3) + atan(1/7) OK: pi/4 = 4*atan(1/5) - atan(1/239) OK: pi/4 = 5*atan(1/7) + 2*atan(3/79) OK: pi/4 = 5*atan(29/278) + 7*atan(3/79) OK: pi/4 = atan(1/2) + atan(1/5) + atan(1/8) OK: pi/4 = 4*atan(1/5) - atan(1/70) + atan(1/99) OK: pi/4 = 5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443) OK: pi/4 = 6*atan(1/8) + 2*atan(1/57) + atan(1/239) OK: pi/4 = 8*atan(1/10) - atan(1/239) - 4*atan(1/515) OK: pi/4 = 12*atan(1/18) + 8*atan(1/57) - 5*atan(1/239) OK: pi/4 = 16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042) OK: pi/4 = 22*atan(1/28) + 2*atan(1/443) - 5*atan(1/1393) - 10*atan(1/11018) OK: pi/4 = 22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149) OK: pi/4 = 44*atan(1/57) + 7*atan(1/239) - 12*atan(1/682) + 24*atan(1/12943) OK: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12943) bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68 *atan(1/12944) bad: pi/4 = 88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 67.9999999994*atan(1/12943)
RPL
RPL does not support fat integers, therefore fat fractions neither, but the precision of floating-point numbers is actually sufficient to detect the incorrect formula and validate the other ones without using any trigonometric function. The 17 formulas to be checked are stored as strings in a global variable; each string is converted into a list of coefficients and real numbers, on which tan(a+b)=(tan(a)+tan(b))/(1-tan(a)*tan(b))
is recursively applied, in a similar way to other languages.
{ "1*arctan(1/2) + 1*arctan(1/3)" "2*arctan(1/3) + 1*arctan(1/7)" "4*arctan(1/5) + -1*arctan(1/239)" "5*arctan(1/7) + 2*arctan(3/79)" "5*arctan(29/278) + 7*arctan(3/79)" "1*arctan(1/2) + 1*arctan(1/5) + 1*arctan(1/8)" "4*arctan(1/5) + -1*arctan(1/70) + 1*arctan(1/99)" "5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)" "6*arctan(1/8) + 2*arctan(1/57) + 1*arctan(1/239)" "8*arctan(1/10) + -1*arctan(1/239) + -4*arctan(1/515)" "12*arctan(1/18) + 8*arctan(1/57) + -5*arctan(1/239)" "16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)" "22*arctan(1/28) + 2*arctan(1/443) + -5*arctan(1/1393) + -10*arctan(1/11018)" "22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)" "44*arctan(1/57) + 7*arctan(1/239) + -12*arctan(1/682) + 24*arctan(1/12943)" "88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)" "88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)" } 'Formulas' STO
RPL code | Comment |
---|---|
≪ IF DUP 1 == THEN DROP ELSE IF DUP 0 < THEN NEG TanEval NEG ELSE DUP2 2 / IP TanEval ROT ROT DUP 2 / IP - TanEval + LAST * 1 - NEG / END END ≫ ‘TanEval’ STO ≪ DUP 2 GET →NUM OVER 1 GET →NUM TanEval SWAP IF DUP SIZE 3 ≥ THEN LIST→ 2 - →LIST ROT ROT DROP2 TanSum SWAP + LAST * 1 - NEG / ELSE DROP END ≫ ‘TanSum’ STO ≪ DUP "+" POS → eq op ≪ IF op THEN eq op 1 + OVER SIZE SUB eq 1 op 1 - SUB ELSE "" eq END "'" DUP ROT SWAP + + STR→ ≫ ≫ 'PopTerm' STO ≪ {} SWAP WHILE DUP "" ≠ REPEAT PopTerm ROT OVER 1 EXGET + SWAP DUP SIZE 1 - EXGET + SWAP END DROP ≫ ‘ParsExp’ STO ≪ 1 CF 0 1 Formulas SIZE FOR f Formulas f GET ParsExp TanSum IF RND 1 == THEN 1 + ELSE 1 SF "INCORRECT: π/4 ≠ " Formulas f GET + SWAP END NEXT →STR IF 1 FS? THEN " others" + END " OK" + ≫ ‘TASK’ STO |
TanEval ( f c -- tan(c*arctan(f)) ) if c = 1 then return f else if c < 0 then return -tan(-c*arctan(f)) else put a = tan((c%2)*arctan(f)) at stack level 3 get b = tan((c-c%2)*arctan(f)) return (a+b)/(-(a*b-1)) TanSum ( { c1 f1 .. cn fn } -- result ) Get tan(c1*arctan(f1)) if input list > 2 items make { c2 f2 .. cn fn } evaluate tan of { c2..fn } and add it to otherwise drop empty list PopTerm ( "T1+T2+..+Tn" -- "T2+..+Tn" 'T1' ) If input string contains "+" then split it else string contains only the last term convert term into algebraic expression ParsExp ( "Machin formula" -- { c1 f1 .. cn fn } ) Scan the formula extract next term extract c and f Drop empty string Initialize flag and counter Scan list of formulas evaluate tan(formula) if ok, increase counter else build error message with incorrect formula Finalize report |
- Output:
2: "INCORRECT: π/4 ≠ 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)" 1: "16 others OK"
Seed7
$ include "seed7_05.s7i";
include "bigint.s7i";
include "bigrat.s7i";
const type: mTerms is array array bigInteger;
const array mTerms: testCases is [] (
[] ([] ( 1_, 1_, 2_), [] ( 1_, 1_, 3_)),
[] ([] ( 2_, 1_, 3_), [] ( 1_, 1_, 7_)),
[] ([] ( 4_, 1_, 5_), [] (-1_, 1_, 239_)),
[] ([] ( 5_, 1_, 7_), [] ( 2_, 3_, 79_)),
[] ([] ( 1_, 1_, 2_), [] ( 1_, 1_, 5_), [] ( 1_, 1_, 8_)),
[] ([] ( 4_, 1_, 5_), [] (-1_, 1_, 70_), [] ( 1_, 1_, 99_)),
[] ([] ( 5_, 1_, 7_), [] ( 4_, 1_, 53_), [] ( 2_, 1_, 4443_)),
[] ([] ( 6_, 1_, 8_), [] ( 2_, 1_, 57_), [] ( 1_, 1_, 239_)),
[] ([] ( 8_, 1_, 10_), [] (-1_, 1_, 239_), [] ( -4_, 1_, 515_)),
[] ([] (12_, 1_, 18_), [] ( 8_, 1_, 57_), [] ( -5_, 1_, 239_)),
[] ([] (16_, 1_, 21_), [] ( 3_, 1_, 239_), [] ( 4_, 3_, 1042_)),
[] ([] (22_, 1_, 28_), [] ( 2_, 1_, 443_), [] ( -5_, 1_, 1393_), [] (-10_, 1_, 11018_)),
[] ([] (22_, 1_, 38_), [] (17_, 7_, 601_), [] ( 10_, 7_, 8149_)),
[] ([] (44_, 1_, 57_), [] ( 7_, 1_, 239_), [] (-12_, 1_, 682_), [] ( 24_, 1_, 12943_)),
[] ([] (88_, 1_, 172_), [] (51_, 1_, 239_), [] ( 32_, 1_, 682_), [] ( 44_, 1_, 5357_), [] (68_, 1_, 12943_)),
[] ([] (88_, 1_, 172_), [] (51_, 1_, 239_), [] ( 32_, 1_, 682_), [] ( 44_, 1_, 5357_), [] (68_, 1_, 12944_))
);
const func bigRational: tanEval (in bigInteger: coef, in bigRational: f) is func
result
var bigRational: tanEval is bigRational.value;
local
var bigRational: a is bigRational.value;
var bigRational: b is bigRational.value;
begin
if coef = 1_ then
tanEval := f;
elsif coef < 0_ then
tanEval := -tanEval(-coef, f);
else
a := tanEval(coef div 2_, f);
b := tanEval(coef - coef div 2_, f);
tanEval := (a + b) / (1_/1_ - a * b);
end if;
end func;
const func bigRational: tans (in mTerms: terms) is func
result
var bigRational: tans is bigRational.value;
local
var bigRational: a is bigRational.value;
var bigRational: b is bigRational.value;
begin
if length(terms) = 1 then
tans := tanEval(terms[1][1], terms[1][2] / terms[1][3]);
else
a := tans(terms[.. length(terms) div 2]);
b := tans(terms[succ(length(terms) div 2) ..]);
tans := (a + b) / (1_/1_ - a * b);
end if;
end func;
const proc: main is func
local
var integer: index is 0;
var array bigInteger: term is 0 times 0_;
begin
for key index range testCases do
write(tans(testCases[index]) = 1_/1_ <& ": pi/4 = ");
for term range testCases[index] do
write([0] ("+", "-")[ord(term[1] < 0_)] <& abs(term[1]) <& "*arctan(" <& term[2] <& "/" <& term[3] <& ")");
end for;
writeln;
end for;
end func;
- Output:
TRUE: pi/4 = +1*arctan(1/2)+1*arctan(1/3) TRUE: pi/4 = +2*arctan(1/3)+1*arctan(1/7) TRUE: pi/4 = +4*arctan(1/5)-1*arctan(1/239) TRUE: pi/4 = +5*arctan(1/7)+2*arctan(3/79) TRUE: pi/4 = +1*arctan(1/2)+1*arctan(1/5)+1*arctan(1/8) TRUE: pi/4 = +4*arctan(1/5)-1*arctan(1/70)+1*arctan(1/99) TRUE: pi/4 = +5*arctan(1/7)+4*arctan(1/53)+2*arctan(1/4443) TRUE: pi/4 = +6*arctan(1/8)+2*arctan(1/57)+1*arctan(1/239) TRUE: pi/4 = +8*arctan(1/10)-1*arctan(1/239)-4*arctan(1/515) TRUE: pi/4 = +12*arctan(1/18)+8*arctan(1/57)-5*arctan(1/239) TRUE: pi/4 = +16*arctan(1/21)+3*arctan(1/239)+4*arctan(3/1042) TRUE: pi/4 = +22*arctan(1/28)+2*arctan(1/443)-5*arctan(1/1393)-10*arctan(1/11018) TRUE: pi/4 = +22*arctan(1/38)+17*arctan(7/601)+10*arctan(7/8149) TRUE: pi/4 = +44*arctan(1/57)+7*arctan(1/239)-12*arctan(1/682)+24*arctan(1/12943) TRUE: pi/4 = +88*arctan(1/172)+51*arctan(1/239)+32*arctan(1/682)+44*arctan(1/5357)+68*arctan(1/12943) FALSE: pi/4 = +88*arctan(1/172)+51*arctan(1/239)+32*arctan(1/682)+44*arctan(1/5357)+68*arctan(1/12944)
Sidef
var equationtext = <<'EOT'
pi/4 = arctan(1/2) + arctan(1/3)
pi/4 = 2*arctan(1/3) + arctan(1/7)
pi/4 = 4*arctan(1/5) - arctan(1/239)
pi/4 = 5*arctan(1/7) + 2*arctan(3/79)
pi/4 = 5*arctan(29/278) + 7*arctan(3/79)
pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)
pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)
pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)
pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)
pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)
pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)
pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)
pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)
pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)
pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
EOT
func parse_eqn(equation) {
static eqn_re = %r{
(^ \s* pi/4 \s* = \s* )? # LHS of equation
(?: # RHS
\s* ( [-+] )? \s*
(?: ( \d+ ) \s* \*)?
\s* arctan\((.*?)\)
)}x
gather {
for lhs,sign,mult,rat in (equation.findall(eqn_re)) {
take([
[+1, -1][sign == '-'] * (mult ? Num(mult) : 1),
Num(rat)
])
}
}
}
func tanEval(coef, f) {
return f if (coef == 1)
return -tanEval(-coef, f) if (coef < 0)
var ca = coef>>1
var cb = (coef - ca)
var (a, b) = (tanEval(ca, f), tanEval(cb, f))
(a + b) / (1 - a*b)
}
func tans(xs) {
var xslen = xs.len
return tanEval(xs[0]...) if (xslen == 1)
var (aa, bb) = xs.part(xslen>>1)
var (a, b) = (tans(aa), tans(bb))
(a + b) / (1 - a*b)
}
var machins = equationtext.lines.map(parse_eqn)
for machin,eqn in (machins ~Z equationtext.lines) {
var ans = tans(machin)
printf("%5s: %s\n", (ans == 1 ? 'OK' : 'ERROR'), eqn)
}
- Output:
OK: pi/4 = arctan(1/2) + arctan(1/3) OK: pi/4 = 2*arctan(1/3) + arctan(1/7) OK: pi/4 = 4*arctan(1/5) - arctan(1/239) OK: pi/4 = 5*arctan(1/7) + 2*arctan(3/79) OK: pi/4 = 5*arctan(29/278) + 7*arctan(3/79) OK: pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) OK: pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) OK: pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) OK: pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) OK: pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) OK: pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) OK: pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) OK: pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) OK: pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) OK: pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) OK: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) ERROR: pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
Tcl
package require Tcl 8.5
# Compute tan(atan(p)+atan(q)) using rationals
proc tadd {p q} {
lassign $p pp pq
lassign $q qp qq
set topp [expr {$pp*$qq + $qp*$pq}]
set topq [expr {$pq*$qq}]
set prodp [expr {$pp*$qp}]
set prodq [expr {$pq*$qq}]
set lowp [expr {$prodq - $prodp}]
set resultp [set gcd1 [expr {$topp * $prodq}]]
set resultq [set gcd2 [expr {$topq * $lowp}]]
# Critical! Normalize using the GCD
while {$gcd2 != 0} {
lassign [list $gcd2 [expr {$gcd1 % $gcd2}]] gcd1 gcd2
}
list [expr {$resultp / abs($gcd1)}] [expr {$resultq / abs($gcd1)}]
}
proc termTan {n a b} {
if {$n < 0} {
set n [expr {-$n}]
set a [expr {-$a}]
}
if {$n == 1} {
return [list $a $b]
}
set k [expr {$n - [set m [expr {$n / 2}]]*2}]
set t2 [termTan $m $a $b]
set m2 [tadd $t2 $t2]
if {$k == 0} {
return $m2
}
return [tadd [termTan $k $a $b] $m2]
}
proc machinTan {terms} {
set sum {0 1}
foreach term $terms {
set sum [tadd $sum [termTan {*}$term]]
}
return $sum
}
# Assumes that the formula is in the very specific form below!
proc parseFormula {formula} {
set RE {(-?\s*\d*\s*\*?)\s*arctan\s*\(\s*(-?\s*\d+)\s*/\s*(-?\s*\d+)\s*\)}
set nospace {" " "" "*" ""}
foreach {all n a b} [regexp -inline -all $RE $formula] {
if {![regexp {\d} $n]} {append n 1}
lappend result [list [string map $nospace $n] [string map $nospace $a] [string map $nospace $b]]
}
return $result
}
foreach formula {
"pi/4 = arctan(1/2) + arctan(1/3)"
"pi/4 = 2*arctan(1/3) + arctan(1/7)"
"pi/4 = 4*arctan(1/5) - arctan(1/239)"
"pi/4 = 5*arctan(1/7) + 2*arctan(3/79)"
"pi/4 = 5*arctan(29/278) + 7*arctan(3/79)"
"pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)"
"pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)"
"pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)"
"pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)"
"pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)"
"pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)"
"pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)"
"pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)"
"pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)"
"pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)"
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)"
"pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)"
} {
if {[tcl::mathop::== {*}[machinTan [parseFormula $formula]]]} {
puts "Yes! '$formula' is true"
} else {
puts "No! '$formula' not true"
}
}
- Output:
Yes! 'pi/4 = arctan(1/2) + arctan(1/3)' is true Yes! 'pi/4 = 2*arctan(1/3) + arctan(1/7)' is true Yes! 'pi/4 = 4*arctan(1/5) - arctan(1/239)' is true Yes! 'pi/4 = 5*arctan(1/7) + 2*arctan(3/79)' is true Yes! 'pi/4 = 5*arctan(29/278) + 7*arctan(3/79)' is true Yes! 'pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)' is true Yes! 'pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)' is true Yes! 'pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)' is true Yes! 'pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)' is true Yes! 'pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)' is true Yes! 'pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)' is true Yes! 'pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)' is true Yes! 'pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)' is true Yes! 'pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)' is true Yes! 'pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)' is true Yes! 'pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)' is true No! 'pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)' not true
Wren
We already have a BigRat class so we use that.
import "./big" for BigRat
import "./fmt" for Fmt
/** represents a term of the form: c * atan(n / d) */
class Term {
construct new(c, n, d) {
_c = c
_n = n
_d = d
}
c { _c }
n { _n }
d { _d }
toString {
var a = "atan(%(n)/%(d))"
return ((_c == 1) ? " + " :
(_c == -1) ? " - " :
(_c < 0) ? " - %(-c)*" : " + %(c)*") + a
}
}
var tanEval // recursive function
tanEval = Fn.new { |c, f|
if (c == 1) return f
if (c < 0) return -tanEval.call(-c, f)
var ca = (c/2).truncate
var cb = c - ca
var a = tanEval.call(ca, f)
var b = tanEval.call(cb, f)
return (a + b) / (BigRat.one - (a * b))
}
var tanSum // recursive function
tanSum = Fn.new { |terms|
if (terms.count == 1) return tanEval.call(terms[0].c, BigRat.new(terms[0].n, terms[0].d))
var half = (terms.count/2).floor
var a = tanSum.call(terms.take(half).toList)
var b = tanSum.call(terms.skip(half).toList)
return (a + b) / (BigRat.one - (a * b))
}
var T = Term // type alias
var termsList = [
[T.new(1, 1, 2), T.new(1, 1, 3)],
[T.new(2, 1, 3), T.new(1, 1, 7)],
[T.new(4, 1, 5), T.new(-1, 1, 239)],
[T.new(5, 1, 7), T.new(2, 3, 79)],
[T.new(5, 29, 278), T.new(7, 3, 79)],
[T.new(1, 1, 2), T.new(1, 1, 5), T.new(1, 1, 8)],
[T.new(4, 1, 5), T.new(-1, 1, 70), T.new(1, 1, 99)],
[T.new(5, 1, 7), T.new(4, 1, 53), T.new(2, 1, 4443)],
[T.new(6, 1, 8), T.new(2, 1, 57), T.new(1, 1, 239)],
[T.new(8, 1, 10), T.new(-1, 1, 239), T.new(-4, 1, 515)],
[T.new(12, 1, 18), T.new(8, 1, 57), T.new(-5, 1, 239)],
[T.new(16, 1, 21), T.new(3, 1, 239), T.new(4, 3, 1042)],
[T.new(22, 1, 28), T.new(2, 1, 443), T.new(-5, 1, 1393), T.new(-10, 1, 11018)],
[T.new(22, 1, 38), T.new(17, 7, 601), T.new(10, 7, 8149)],
[T.new(44, 1, 57), T.new(7, 1, 239), T.new(-12, 1, 682), T.new(24, 1, 12943)],
[T.new(88, 1, 172), T.new(51, 1, 239), T.new(32, 1, 682), T.new(44, 1, 5357), T.new(68, 1, 12943)],
[T.new(88, 1, 172), T.new(51, 1, 239), T.new(32, 1, 682), T.new(44, 1, 5357), T.new(68, 1, 12944)]
]
for (terms in termsList) {
var f = Fmt.swrite("$-5s: 1 == tan(", tanSum.call(terms) == BigRat.one)
System.write(f)
System.write(terms[0].toString.skip(3).join())
for (i in 1...terms.count) System.write(terms[i])
System.print(")")
}
- Output:
true : 1 == tan(atan(1/2) + atan(1/3)) true : 1 == tan(2*atan(1/3) + atan(1/7)) true : 1 == tan(4*atan(1/5) - atan(1/239)) true : 1 == tan(5*atan(1/7) + 2*atan(3/79)) true : 1 == tan(5*atan(29/278) + 7*atan(3/79)) true : 1 == tan(atan(1/2) + atan(1/5) + atan(1/8)) true : 1 == tan(4*atan(1/5) - atan(1/70) + atan(1/99)) true : 1 == tan(5*atan(1/7) + 4*atan(1/53) + 2*atan(1/4443)) true : 1 == tan(6*atan(1/8) + 2*atan(1/57) + atan(1/239)) true : 1 == tan(8*atan(1/10) - atan(1/239) - 4*atan(1/515)) true : 1 == tan(12*atan(1/18) + 8*atan(1/57) - 5*atan(1/239)) true : 1 == tan(16*atan(1/21) + 3*atan(1/239) + 4*atan(3/1042)) true : 1 == tan(22*atan(1/28) + 2*atan(1/443) - 5*atan(1/1393) - 10*atan(1/11018)) true : 1 == tan(22*atan(1/38) + 17*atan(7/601) + 10*atan(7/8149)) true : 1 == tan(44*atan(1/57) + 7*atan(1/239) - 12*atan(1/682) + 24*atan(1/12943)) true : 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12943)) false: 1 == tan(88*atan(1/172) + 51*atan(1/239) + 32*atan(1/682) + 44*atan(1/5357) + 68*atan(1/12944))
XPL0
code ChOut=8, Text=12; \intrinsic routines
int Number(18); \numbers from equations
def LF=$0A; \ASCII line feed (end-of-line character)
func Parse(S); \Convert numbers in string S to binary in Number array
char S;
int I, Neg;
proc GetNum; \Get number from string S
int N;
[while S(0)<^0 ! S(0)>^9 do S:= S+1;
N:= S(0)-^0; S:= S+1;
while S(0)>=^0 & S(0)<=^9 do
[N:= N*10 + S(0) - ^0; S:= S+1];
Number(I):= N; I:= I+1;
];
[while S(0)#^= do S:= S+1; \skip to "="
I:= 0;
loop [Neg:= false; \assume positive term
loop [S:= S+1; \next char
case S(0) of
LF: [Number(I):= 0; return S+1]; \mark end of array
^-: Neg:= true; \term is negative
^a: [Number(I):= 1; I:= I+1; quit] \no coefficient so use 1
other if S(0)>=^0 & S(0)<=^9 then \if digit
[S:= S-1; GetNum; quit]; \backup and get number
];
GetNum; \numerator
if Neg then Number(I-1):= -Number(I-1); \tan(-a) = -tan(a)
GetNum; \denominator
];
];
func GCD(U, V); \Return the greatest common divisor of U and V
int U, V;
int T;
[while V do \Euclid's method
[T:= U; U:= V; V:= rem(T/V)];
return abs(U);
];
proc Verify; \Verify that tangent of equation = 1 (i.e: E = F)
int E, F, I, J;
proc Machin(A, B, C, D);
int A, B, C, D;
int Div;
\tan(a+b) = (tan(a) + tan(b)) / (1 - tan(a)*tan(b))
\tan(arctan(A/B) + arctan(C/D))
\ = (tan(arctan(A/B)) + tan(arctan(C/D))) / (1 - tan(arctan(A/B))*tan(arctan(C/D)))
\ = (A/B + C/D) / (1 - A/B*C/D)
\ = (A*D/B*D + B*C/B*D) / (B*D/B*D - A*C/B*D)
\ = (A*D + B*C) / (B*D - A*C)
[E:= A*D + B*C; F:= B*D - A*C;
Div:= GCD(E, F); \keep integers from getting too big
E:= E/Div; F:= F/Div;
];
[E:= 0; F:= 1; I:= 0;
while Number(I) do
[for J:= 1 to Number(I) do
Machin(E, F, Number(I+1), Number(I+2));
I:= I+3;
];
Text(0, if E=F then "Yes " else "No ");
];
char S, SS; int I;
[S:= "pi/4 = arctan(1/2) + arctan(1/3)
pi/4 = 2*arctan(1/3) + arctan(1/7)
pi/4 = 4*arctan(1/5) - arctan(1/239)
pi/4 = 5*arctan(1/7) + 2*arctan(3/79)
pi/4 = 5*arctan(29/278) + 7*arctan(3/79)
pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8)
pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99)
pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443)
pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239)
pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515)
pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239)
pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042)
pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018)
pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149)
pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943)
pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)
"; \Python version of equations (thanks!)
for I:= 1 to 17 do
[SS:= S; \save start of string line
S:= Parse(S); \returns start of next line
Verify; \correct Machin equation? Yes or No
repeat ChOut(0, SS(0)); SS:= SS+1 until SS(0)=LF; ChOut(0, LF); \show equation
];
]
- Output:
Yes pi/4 = arctan(1/2) + arctan(1/3) Yes pi/4 = 2*arctan(1/3) + arctan(1/7) Yes pi/4 = 4*arctan(1/5) - arctan(1/239) Yes pi/4 = 5*arctan(1/7) + 2*arctan(3/79) Yes pi/4 = 5*arctan(29/278) + 7*arctan(3/79) Yes pi/4 = arctan(1/2) + arctan(1/5) + arctan(1/8) Yes pi/4 = 4*arctan(1/5) - arctan(1/70) + arctan(1/99) Yes pi/4 = 5*arctan(1/7) + 4*arctan(1/53) + 2*arctan(1/4443) Yes pi/4 = 6*arctan(1/8) + 2*arctan(1/57) + arctan(1/239) Yes pi/4 = 8*arctan(1/10) - arctan(1/239) - 4*arctan(1/515) Yes pi/4 = 12*arctan(1/18) + 8*arctan(1/57) - 5*arctan(1/239) Yes pi/4 = 16*arctan(1/21) + 3*arctan(1/239) + 4*arctan(3/1042) Yes pi/4 = 22*arctan(1/28) + 2*arctan(1/443) - 5*arctan(1/1393) - 10*arctan(1/11018) Yes pi/4 = 22*arctan(1/38) + 17*arctan(7/601) + 10*arctan(7/8149) Yes pi/4 = 44*arctan(1/57) + 7*arctan(1/239) - 12*arctan(1/682) + 24*arctan(1/12943) Yes pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12943) No pi/4 = 88*arctan(1/172) + 51*arctan(1/239) + 32*arctan(1/682) + 44*arctan(1/5357) + 68*arctan(1/12944)