|
Groovy/FAQ/Числа
Материал из Wiki.crossplatform.ru
Checking Whether a String Is a Valid Number
//----------------------------------------------------------------------------------
// four approaches possible (shown for Integers, similar for floats, double etc.):
// (1) NumberFormat.getInstance().parse(s) // getInstance() can take locale
// (2) Integer.parseInt(s)
// (3) new Integer(s)
// (4) regex
import java.text.*
int nb = 0
try {
nb = NumberFormat.getInstance().parse('33.5') // '.5' will be ignored
nb = NumberFormat.getInstance().parse('abc')
} catch (ParseException ex) {
assert ex.getMessage().contains('abc')
}
assert nb == 33
try {
nb = Integer.parseInt('34')
assert nb == 34
nb = new Integer('35')
nb = Integer.parseInt('abc')
} catch (NumberFormatException ex) {
assert ex.getMessage().contains('abc')
}
assert nb == 35
integerPattern = /^[+-]?\d+$/
assert '-36' =~ integerPattern
assert !('abc' =~ integerPattern)
decimalPattern = /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
assert '37.5' =~ decimalPattern
//----------------------------------------------------------------------------------
Comparing Floating-Point Numbers
//----------------------------------------------------------------------------------
// Groovy defaults to BigDecimal if you don't use an explicit float or double
wage = 5.36
week = 40 * wage
assert "One week's wage is: \$$week" == /One week's wage is: $214.40/
// if you want to use explicit doubles and floats you can still use
// printf in version 5, 6 or 7 JVMs
// printf('%5.2f', week as double)
// => 214.40
//----------------------------------------------------------------------------------
Rounding Floating-Point Numbers
//----------------------------------------------------------------------------------
a = 0.255
b = a.setScale(2, BigDecimal.ROUND_HALF_UP);
assert a.toString() == '0.255'
assert b.toString() == '0.26'
a = [3.3 , 3.5 , 3.7, -3.3] as double[]
// warning rint() rounds to nearest integer - slightly different to Perl's int()
rintExpected = [3.0, 4.0, 4.0, -3.0] as double[]
floorExpected = [3.0, 3.0, 3.0, -4.0] as double[]
ceilExpected = [4.0, 4.0, 4.0, -3.0] as double[]
a.eachWithIndex{ val, i ->
assert Math.rint(val) == rintExpected[i]
assert Math.floor(val) == floorExpected[i]
assert Math.ceil(val) == ceilExpected[i]
}
//----------------------------------------------------------------------------------
Converting Between Binary and Decimal
//----------------------------------------------------------------------------------
assert Integer.parseInt('0110110', 2) == 54
assert Integer.toString(54, 2) == '110110'
// also works for other radix values, e.g. hex
assert Integer.toString(60, 16) == '3c'
//----------------------------------------------------------------------------------
Operating on a Series of Integers
//----------------------------------------------------------------------------------
x = 3; y = 20
for (i in x..y) {
//i is set to every integer from x to y, inclusive
}
(x..<y).each {
//implicit closure variable it is set to every integer from x up to but excluding y
}
assert (x..y).step(7) == [3, 10, 17]
years = []
(5..<13).each{ age -> years += age }
assert years == [5, 6, 7, 8, 9, 10, 11, 12]
//----------------------------------------------------------------------------------
Working with Roman Numerals
//----------------------------------------------------------------------------------
// We can add additional methods to the Integer class
class IntegerCategory {
static def romanMap = [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']
static getRoman(Integer self) {
def remains = self
def text = ''
romanMap.keySet().sort().reverse().each{ key ->
while (remains >= key) {
remains -= key
text += romanMap[key]
}
}
return text
}
static int parseRoman(Object self, String input) {
def ustr = input.toUpperCase()
int sum = 0
romanMap.keySet().sort().reverse().each{ key ->
while (ustr.startsWith(romanMap[key])) {
sum += key
ustr -= romanMap[key]
}
}
return sum
}
}
use(IntegerCategory) {
int fifteen = 15
assert fifteen.roman == 'XV'
assert parseRoman('XXVI') == 26
for (i in 1..3900) {
assert i == parseRoman(i.roman)
}
}
//----------------------------------------------------------------------------------
Generating Random Numbers
//----------------------------------------------------------------------------------
random = new Random()
100.times{
next = random.nextInt(50) + 25
assert next > 24
assert next < 76
}
chars = []
['A'..'Z','a'..'z','0'..'9',('!@$%^&*' as String[]).toList()].each{chars += it}
password = (1..8).collect{ chars[random.nextInt(chars.size())] }.join()
assert password.size() == 8
//----------------------------------------------------------------------------------
Generating Different Random Numbers
//----------------------------------------------------------------------------------
// By default Groovy uses Java's Random facilities which use the current time
// as the initial seed. This always changes but does so slowly over time.
// You are free to select a better seed if you want greater randomness or
// use the same one each time if you need repeatability.
long seed = System.currentTimeMillis()
random1 = new Random(seed)
random2 = new Random(seed)
assert random1.nextInt() == random2.nextInt()
//----------------------------------------------------------------------------------
Making Numbers Even More Random
//----------------------------------------------------------------------------------
// java.util.Random which Groovy uses already uses a 48-bit seed
// You can make use 64 not 48 bits (and make better use of the 48 bits) see here:
// http://alife.co.uk/nonrandom/
// You can choose a better seed, e.g. Ant uses:
seed = System.currentTimeMillis() + Runtime.runtime.freeMemory()
// You can accept input from the user, e.g.
// http://examples.oreilly.com/javacrypt/files/oreilly/jonathan/util/Seeder.java
//----------------------------------------------------------------------------------
Generating Biased Random Numbers
//----------------------------------------------------------------------------------
// use Java's Random.nextGaussian() method
random = new Random()
mean = 25
sdev = 2
salary = random.nextGaussian() * sdev + mean
// script:
printf 'You have been hired at \$%.2f', salary
// => You have been hired at $25.05
//----------------------------------------------------------------------------------
Doing Trigonometry in Degrees, not Radians
//----------------------------------------------------------------------------------
// radians = Math.toRadians(degrees)
assert Math.toRadians(90) == Math.PI / 2
// degrees = Math.toDegrees(radians)
assert Math.toDegrees(Math.PI) == 180
//----------------------------------------------------------------------------------
Calculating More Trigonometric Functions
//----------------------------------------------------------------------------------
// use Java's trigonometry methods in java.lang.Math
//----------------------------------------------------------------------------------
t = Math.tan(1.5)
assert t > 14.1 && t < 14.11
ac = Math.acos(0.1)
assert ac > 1.47 && ac < 1.48
//----------------------------------------------------------------------------------
Taking Logarithms
//----------------------------------------------------------------------------------
assert Math.log(Math.E) == 1
assert Math.log10(10000) == 4
def logn(base, val) { Math.log(val)/Math.log(base) }
assert logn(2, 1024) == 10
//----------------------------------------------------------------------------------
Multiplying Matrices
//----------------------------------------------------------------------------------
// there are several Java Matrix packages available, e.g.
// http://math.nist.gov/javanumerics/jama
import Jama.Matrix
matrix1 = new Matrix([
[3, 2, 3],
[5, 9, 8]
] as double[][])
matrix2 = new Matrix([
[4, 7],
[9, 3],
[8, 1]
] as double[][])
expectedArray = [[54.0, 30.0], [165.0, 70.0]] as double[][]
productArray = matrix1.times(matrix2).array
for (i in 0..<productArray.size()) {
assert productArray[i] == expectedArray[i]
}
//----------------------------------------------------------------------------------
Using Complex Numbers
//----------------------------------------------------------------------------------
// there are several Java Complex number packages, e.g.:
// http://jakarta.apache.org/commons/math/userguide/complex.html
import org.apache.commons.math.complex.Complex
a = new Complex(3, 5) // 3 + 5i
b = new Complex(2, -2) // 2 - 2i
expected = new Complex (16, 4) // 16 + 4i
assert expected == a * b
//----------------------------------------------------------------------------------
Converting Between Octal and Hexadecimal
//----------------------------------------------------------------------------------
assert Integer.parseInt('101', 16) == 257
assert Integer.parseInt('077', 8) == 63
//----------------------------------------------------------------------------------
// conversionScript:
print 'Gimme a number in decimal, octal, or hex: '
reader = new BufferedReader(new InputStreamReader(System.in))
input = reader.readLine().trim()
switch(input) {
case ~'^0x\\d+':
number = Integer.parseInt(input.substring(2), 16); break
case ~'^0\\d+':
number = Integer.parseInt(input.substring(1), 8); break
default:
number = Integer.parseInt(input)
}
println 'Decimal value: ' + number
// permissionScript:
print 'Enter file permission in octal: '
input = new BufferedReader(new InputStreamReader(System.in))
num = input.readLine().trim()
permission = Integer.parseInt(num, 8)
println 'Decimal value: ' + permission
//----------------------------------------------------------------------------------
Putting Commas in Numbers
//----------------------------------------------------------------------------------
nf = NumberFormat.getInstance()
assert nf.format(-1740525205) == '-1,740,525,205'
//----------------------------------------------------------------------------------
Printing Correct Plurals
//----------------------------------------------------------------------------------
def timeMessage(hour) { 'It took ' + hour + ' hour' + (hour == 1 ? '' : 's') }
assert 'It took 1 hour' == timeMessage(1)
assert 'It took 2 hours' == timeMessage(2)
// you can also use Java's ChoiceFormat
// overkill for this example but extensible and compatible with MessageFormat
limits = [1, ChoiceFormat.nextDouble(1)] as double[]
names = ['century', 'centuries'] as String[]
choice = new ChoiceFormat(limits, names)
numCenturies = 1
expected = 'It took 1 century'
assert expected == "It took $numCenturies " + choice.format(numCenturies)
// an alternate constructor syntax
choice = new ChoiceFormat('0#are no files|1#is one file|2#are multiple files')
assert choice.format(3) == 'are multiple files'
// more complex pluralization can be done with Java libraries, e.g.:
// http://www.elvis.ac.nz/brain?PluralizationMapping
// org.springframework.util.Pluralizer within the Spring Framework (springframework.org)
//----------------------------------------------------------------------------------
Program: Calculating Prime Factors
//----------------------------------------------------------------------------------
// calculating prime factors
def factorize(BigInteger orig) {
factors = [:]
def addFactor = { x -> if (factors[x]) factors[x] += 1 else factors[x] = 1 }
n = orig
i = 2
sqi = 4 // square of i
while (sqi <= n) {
while (n.remainder(i) == 0) {
n /= i
addFactor i
}
// we take advantage of the fact that (i+1)**2 = i**2 + 2*i + 1
sqi += 2 * i + 1
i += 1
}
if ((n != 1) && (n != orig)) addFactor n
return factors
}
def pretty(factors) {
if (!factors) return "PRIME"
sb = new StringBuffer()
factors.keySet().sort().each { key ->
sb << key
if (factors[key] > 1) sb << "**" + factors[key]
sb << " "
}
return sb.toString().trim()
}
assert pretty(factorize(2178)) == '2 3**2 11**2'
assert pretty(factorize(39887)) == 'PRIME'
assert pretty(factorize(239322000000000000000000)) == '2**19 3 5**18 39887'
//----------------------------------------------------------------------------------
|