Skip to content

Commit de34eca

Browse files
committed
#65 fn: MOD, MROUND, MULTINOMIAL, MUNIT, ODD, PI, RADIANS, RAND, RANDBETWEEN, ROMAN
1 parent 5f29af2 commit de34eca

File tree

2 files changed

+382
-32
lines changed

2 files changed

+382
-32
lines changed

calc.go

Lines changed: 313 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
package excelize
1313

1414
import (
15+
"bytes"
1516
"container/list"
1617
"errors"
1718
"fmt"
1819
"math"
20+
"math/rand"
1921
"reflect"
2022
"strconv"
2123
"strings"
24+
"time"
2225

2326
"github.com/xuri/efp"
2427
)
@@ -1715,6 +1718,168 @@ func (fn *formulaFuncs) MDETERM(argsList *list.List) (result string, err error)
17151718
return
17161719
}
17171720

1721+
// MOD function returns the remainder of a division between two supplied
1722+
// numbers. The syntax of the function is:
1723+
//
1724+
// MOD(number,divisor)
1725+
//
1726+
func (fn *formulaFuncs) MOD(argsList *list.List) (result string, err error) {
1727+
if argsList.Len() != 2 {
1728+
err = errors.New("MOD requires 2 numeric arguments")
1729+
return
1730+
}
1731+
var number, divisor float64
1732+
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1733+
return
1734+
}
1735+
if divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil {
1736+
return
1737+
}
1738+
if divisor == 0 {
1739+
err = errors.New(formulaErrorDIV)
1740+
return
1741+
}
1742+
trunc, rem := math.Modf(number / divisor)
1743+
if rem < 0 {
1744+
trunc--
1745+
}
1746+
result = fmt.Sprintf("%g", number-divisor*trunc)
1747+
return
1748+
}
1749+
1750+
// MROUND function rounds a supplied number up or down to the nearest multiple
1751+
// of a given number. The syntax of the function is:
1752+
//
1753+
// MOD(number,multiple)
1754+
//
1755+
func (fn *formulaFuncs) MROUND(argsList *list.List) (result string, err error) {
1756+
if argsList.Len() != 2 {
1757+
err = errors.New("MROUND requires 2 numeric arguments")
1758+
return
1759+
}
1760+
var number, multiple float64 = 0, 1
1761+
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1762+
return
1763+
}
1764+
if multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil {
1765+
return
1766+
}
1767+
if multiple == 0 {
1768+
err = errors.New(formulaErrorNUM)
1769+
return
1770+
}
1771+
if multiple < 0 && number > 0 ||
1772+
multiple > 0 && number < 0 {
1773+
err = errors.New(formulaErrorNUM)
1774+
return
1775+
}
1776+
number, res := math.Modf(number / multiple)
1777+
if math.Trunc(res+0.5) > 0 {
1778+
number++
1779+
}
1780+
result = fmt.Sprintf("%g", number*multiple)
1781+
return
1782+
}
1783+
1784+
// MULTINOMIAL function calculates the ratio of the factorial of a sum of
1785+
// supplied values to the product of factorials of those values. The syntax of
1786+
// the function is:
1787+
//
1788+
// MULTINOMIAL(number1,[number2],...)
1789+
//
1790+
func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) (result string, err error) {
1791+
var val, num, denom float64 = 0, 0, 1
1792+
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
1793+
token := arg.Value.(formulaArg)
1794+
if token.Value == "" {
1795+
continue
1796+
}
1797+
if val, err = strconv.ParseFloat(token.Value, 64); err != nil {
1798+
return
1799+
}
1800+
num += val
1801+
denom *= fact(val)
1802+
}
1803+
result = fmt.Sprintf("%g", fact(num)/denom)
1804+
return
1805+
}
1806+
1807+
// MUNIT function returns the unit matrix for a specified dimension. The
1808+
// syntax of the function is:
1809+
//
1810+
// MUNIT(dimension)
1811+
//
1812+
func (fn *formulaFuncs) MUNIT(argsList *list.List) (result string, err error) {
1813+
if argsList.Len() != 1 {
1814+
err = errors.New("MUNIT requires 1 numeric argument")
1815+
return
1816+
}
1817+
var dimension int
1818+
if dimension, err = strconv.Atoi(argsList.Front().Value.(formulaArg).Value); err != nil {
1819+
return
1820+
}
1821+
matrix := make([][]float64, 0, dimension)
1822+
for i := 0; i < dimension; i++ {
1823+
row := make([]float64, dimension)
1824+
for j := 0; j < dimension; j++ {
1825+
if i == j {
1826+
row[j] = float64(1.0)
1827+
} else {
1828+
row[j] = float64(0.0)
1829+
}
1830+
}
1831+
matrix = append(matrix, row)
1832+
}
1833+
return
1834+
}
1835+
1836+
// ODD function ounds a supplied number away from zero (i.e. rounds a positive
1837+
// number up and a negative number down), to the next odd number. The syntax
1838+
// of the function is:
1839+
//
1840+
// ODD(number)
1841+
//
1842+
func (fn *formulaFuncs) ODD(argsList *list.List) (result string, err error) {
1843+
if argsList.Len() != 1 {
1844+
err = errors.New("ODD requires 1 numeric argument")
1845+
return
1846+
}
1847+
var number float64
1848+
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1849+
return
1850+
}
1851+
if number == 0 {
1852+
result = "1"
1853+
return
1854+
}
1855+
sign := math.Signbit(number)
1856+
m, frac := math.Modf((number - 1) / 2)
1857+
val := m*2 + 1
1858+
if frac != 0 {
1859+
if !sign {
1860+
val += 2
1861+
} else {
1862+
val -= 2
1863+
}
1864+
}
1865+
result = fmt.Sprintf("%g", val)
1866+
return
1867+
}
1868+
1869+
// PI function returns the value of the mathematical constant π (pi), accurate
1870+
// to 15 digits (14 decimal places). The syntax of the function is:
1871+
//
1872+
// PI()
1873+
//
1874+
func (fn *formulaFuncs) PI(argsList *list.List) (result string, err error) {
1875+
if argsList.Len() != 0 {
1876+
err = errors.New("PI accepts no arguments")
1877+
return
1878+
}
1879+
result = fmt.Sprintf("%g", math.Pi)
1880+
return
1881+
}
1882+
17181883
// POWER function calculates a given number, raised to a supplied power.
17191884
// The syntax of the function is:
17201885
//
@@ -1765,6 +1930,154 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error)
17651930
return
17661931
}
17671932

1933+
// QUOTIENT function returns the integer portion of a division between two
1934+
// supplied numbers. The syntax of the function is:
1935+
//
1936+
// QUOTIENT(numerator,denominator)
1937+
//
1938+
func (fn *formulaFuncs) QUOTIENT(argsList *list.List) (result string, err error) {
1939+
if argsList.Len() != 2 {
1940+
err = errors.New("QUOTIENT requires 2 numeric arguments")
1941+
return
1942+
}
1943+
var x, y float64
1944+
if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1945+
return
1946+
}
1947+
if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil {
1948+
return
1949+
}
1950+
if y == 0 {
1951+
err = errors.New(formulaErrorDIV)
1952+
return
1953+
}
1954+
result = fmt.Sprintf("%g", math.Trunc(x/y))
1955+
return
1956+
}
1957+
1958+
// RADIANS function converts radians into degrees. The syntax of the function is:
1959+
//
1960+
// RADIANS(angle)
1961+
//
1962+
func (fn *formulaFuncs) RADIANS(argsList *list.List) (result string, err error) {
1963+
if argsList.Len() != 1 {
1964+
err = errors.New("RADIANS requires 1 numeric argument")
1965+
return
1966+
}
1967+
var angle float64
1968+
if angle, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1969+
return
1970+
}
1971+
result = fmt.Sprintf("%g", math.Pi/180.0*angle)
1972+
return
1973+
}
1974+
1975+
// RAND function generates a random real number between 0 and 1. The syntax of
1976+
// the function is:
1977+
//
1978+
// RAND()
1979+
//
1980+
func (fn *formulaFuncs) RAND(argsList *list.List) (result string, err error) {
1981+
if argsList.Len() != 0 {
1982+
err = errors.New("RAND accepts no arguments")
1983+
return
1984+
}
1985+
result = fmt.Sprintf("%g", rand.New(rand.NewSource(time.Now().UnixNano())).Float64())
1986+
return
1987+
}
1988+
1989+
// RANDBETWEEN function generates a random integer between two supplied
1990+
// integers. The syntax of the function is:
1991+
//
1992+
// RANDBETWEEN(bottom,top)
1993+
//
1994+
func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) (result string, err error) {
1995+
if argsList.Len() != 2 {
1996+
err = errors.New("RANDBETWEEN requires 2 numeric arguments")
1997+
return
1998+
}
1999+
var bottom, top int64
2000+
if bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).Value, 10, 64); err != nil {
2001+
return
2002+
}
2003+
if top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).Value, 10, 64); err != nil {
2004+
return
2005+
}
2006+
if top < bottom {
2007+
err = errors.New(formulaErrorNUM)
2008+
return
2009+
}
2010+
result = fmt.Sprintf("%g", float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(top-bottom+1)+bottom))
2011+
return
2012+
}
2013+
2014+
// romanNumerals defined a numeral system that originated in ancient Rome and
2015+
// remained the usual way of writing numbers throughout Europe well into the
2016+
// Late Middle Ages.
2017+
type romanNumerals struct {
2018+
n float64
2019+
s string
2020+
}
2021+
2022+
var romanTable = [][]romanNumerals{{{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
2023+
{{1000, "M"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {95, "VC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
2024+
{{1000, "M"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
2025+
{{1000, "M"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
2026+
{{1000, "M"}, {999, "IM"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {499, "ID"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}}
2027+
2028+
// ROMAN function converts an arabic number to Roman. I.e. for a supplied
2029+
// integer, the function returns a text string depicting the roman numeral
2030+
// form of the number. The syntax of the function is:
2031+
//
2032+
// ROMAN(number,[form])
2033+
//
2034+
func (fn *formulaFuncs) ROMAN(argsList *list.List) (result string, err error) {
2035+
if argsList.Len() == 0 {
2036+
err = errors.New("ROMAN requires at least 1 argument")
2037+
return
2038+
}
2039+
if argsList.Len() > 2 {
2040+
err = errors.New("ROMAN allows at most 2 arguments")
2041+
return
2042+
}
2043+
var number float64
2044+
var form int
2045+
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
2046+
return
2047+
}
2048+
if argsList.Len() > 1 {
2049+
if form, err = strconv.Atoi(argsList.Back().Value.(formulaArg).Value); err != nil {
2050+
return
2051+
}
2052+
if form < 0 {
2053+
form = 0
2054+
} else if form > 4 {
2055+
form = 4
2056+
}
2057+
}
2058+
decimalTable := romanTable[0]
2059+
switch form {
2060+
case 1:
2061+
decimalTable = romanTable[1]
2062+
case 2:
2063+
decimalTable = romanTable[2]
2064+
case 3:
2065+
decimalTable = romanTable[3]
2066+
case 4:
2067+
decimalTable = romanTable[4]
2068+
}
2069+
val := math.Trunc(number)
2070+
buf := bytes.Buffer{}
2071+
for _, r := range decimalTable {
2072+
for val >= r.n {
2073+
buf.WriteString(r.s)
2074+
val -= r.n
2075+
}
2076+
}
2077+
result = buf.String()
2078+
return
2079+
}
2080+
17682081
// SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied
17692082
// number. I.e. if the number is positive, the Sign function returns +1, if
17702083
// the number is negative, the function returns -1 and if the number is 0
@@ -1840,28 +2153,3 @@ func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) {
18402153
result = fmt.Sprintf("%g", sum)
18412154
return
18422155
}
1843-
1844-
// QUOTIENT function returns the integer portion of a division between two
1845-
// supplied numbers. The syntax of the function is:
1846-
//
1847-
// QUOTIENT(numerator,denominator)
1848-
//
1849-
func (fn *formulaFuncs) QUOTIENT(argsList *list.List) (result string, err error) {
1850-
if argsList.Len() != 2 {
1851-
err = errors.New("QUOTIENT requires 2 numeric arguments")
1852-
return
1853-
}
1854-
var x, y float64
1855-
if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil {
1856-
return
1857-
}
1858-
if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil {
1859-
return
1860-
}
1861-
if y == 0 {
1862-
err = errors.New(formulaErrorDIV)
1863-
return
1864-
}
1865-
result = fmt.Sprintf("%g", math.Trunc(x/y))
1866-
return
1867-
}

0 commit comments

Comments
 (0)