|
12 | 12 | package excelize |
13 | 13 |
|
14 | 14 | import ( |
| 15 | + "bytes" |
15 | 16 | "container/list" |
16 | 17 | "errors" |
17 | 18 | "fmt" |
18 | 19 | "math" |
| 20 | + "math/rand" |
19 | 21 | "reflect" |
20 | 22 | "strconv" |
21 | 23 | "strings" |
| 24 | + "time" |
22 | 25 |
|
23 | 26 | "github.com/xuri/efp" |
24 | 27 | ) |
@@ -1715,6 +1718,168 @@ func (fn *formulaFuncs) MDETERM(argsList *list.List) (result string, err error) |
1715 | 1718 | return |
1716 | 1719 | } |
1717 | 1720 |
|
| 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 | + |
1718 | 1883 | // POWER function calculates a given number, raised to a supplied power. |
1719 | 1884 | // The syntax of the function is: |
1720 | 1885 | // |
@@ -1765,6 +1930,154 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error) |
1765 | 1930 | return |
1766 | 1931 | } |
1767 | 1932 |
|
| 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 | + |
1768 | 2081 | // SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied |
1769 | 2082 | // number. I.e. if the number is positive, the Sign function returns +1, if |
1770 | 2083 | // 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) { |
1840 | 2153 | result = fmt.Sprintf("%g", sum) |
1841 | 2154 | return |
1842 | 2155 | } |
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