Why is a double primitive a BigDecimal in groovy - groovy

I call an overloaded method (assertThat) which has one signature with a BigDecimal parameter and another one with double primitive parameter.
When I launch this snippet in groovy, it calls the one with BigDecimal parameter when I was expecting the double primitive parameter one to be called.
double[] erreur = Seg.erreur(xtab, ytab, 0, 2)
Assertions.assertThat(erreur[1]).isEqualTo(-0.3333333333333333)
Can someone explain me why ?
Thanks in advance.

By default, a decimal number in groovy is a BigDecimal. If you want it to be a double, you should use the suffix D or d:
From Number type suffixes in the docs:
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')

Your isEqualsTo() is passing a BigDecimal as parameter, whereas your assertThat() is passing a double. Just add a d at the end of that -0.3333333333333333 and it should work:
import static org.assertj.core.api.Assertions.assertThat
class Doubles extends GroovyTestCase {
void testAssertions() {
double[] erreur = [0.1, -0.3333333333333333, 0.3]
assertThat(erreur[1]).isEqualTo(-0.3333333333333333d)
}
}

Related

Groovy documentation for passing an Integer argument to a BigDecimal parameter?

When I have a Java method that takes a BigDecimal parameter:
public void setAmount(BigDecimal amount)
then I can call it from Groovy using an integer argument like
m.setAmount(11)
Can anybody point me to Groovy documentation where this type coercion (?) is defined?
Extract from https://docs.groovy-lang.org/docs/next/html/documentation/core-semantics.html#_method_resolution
An argument o of type A can be used for a parameter of type T if and only if:
...
or T and A derive from java.lang.Number and conform to the same rules as assignment of numbers
When I then look at the referenced rules for "assignment of numbers", there is no mention of T being BigDecimal:
https://docs.groovy-lang.org/docs/next/html/documentation/core-semantics.html#number-assignment
In this question Converting Integer to BigDecimal in Groovy the answer gives a reference to Groovy's BigDecimalCachedClasscoerceArgument(Object argument).
That method now even has a simpler implementation:
public Object coerceArgument(Object argument) {
if (argument instanceof Number) {
return NumberMath.toBigDecimal((Number) argument);
}
return argument;
}
So: Is the documentation just outdated?

Groovy: Constructor hash collision

I have the following groovy code:
def script
String credentials_id
String repository_path
String relative_directory
String repository_url
CredentialsWrapper(script, credentials_id, repository_name, repository_group, relative_directory=null) {
this(script, credentials_id, 'git#gitlab.foo.com:' + repository_group +'/' + repository_name + '.git', relative_directory);
}
CredentialsWrapper(script, credentials_id, repository_url, relative_directory=null) {
this.script = script;
this.credentials_id = credentials_id;
this.repository_url = repository_url;
if (null == relative_directory) {
int lastSeparatorIndex = repository_url.lastIndexOf("/");
int indexOfExt = repository_url.indexOf(".git");
this.relative_directory = repository_url.substring(lastSeparatorIndex+1, indexOfExt);
}
}
Jenkins gives me the following:
Unable to compile class com.foo.CredentialsWrapper due to hash collision in constructors # line 30, column 7.
I do not understand why, the constructors are different, they do not have the same number of arguments.
Also, "script" is an instance from "WorkflowScript", but I do not know what I should import to access this class, which would allow me to declare script explicitly instead of using "def"
Any idea ?
When you call the Constructor with four parameters, would you like to call the first or the second one?
If you write an constructor/method with default values, groovy will actually generate two or more versions.
So
Test(String x, String y ="test")
will result in
Test(String x, String y) {...}
and
Test(String x) {new Test(x, "test")}
So your code would like to compile to 4 constructors, but it contains the constructor with the signature
CredentialsWrapper(def, def, def, def)
two times.
If I understand your code correctly, you can omit one or both of the =null. The result will be the same, but you will get only two or three signatures. Then you can choose between both versions by calling calling them with the right parameter count.

How do I round a number in Groovy?

How do I round a number in Groovy? I would like to keep 2 decimal places.
For example (pseudo-code):
round(1.2334695) = 1.23
round(1.2686589) = 1.27
If you're dealing with doubles or floats
You can simply use
assert xyz == 1.789
xyz.round(1) == 1.8
xyz.round(2) == 1.79
You can use:
Math.round(x * 100) / 100
If x is a BigDecimal (the default in Groovy), this will be exact.
Use mixin.
class Rounding {
public BigDecimal round(int n) {
return setScale(n, BigDecimal.ROUND_HALF_UP);
}
}
Add this to your startup class and round() is a first-class method of BigDecimal:
BigDecimal.mixin Rounding
Test cases:
assert (new BigDecimal("1.27")) == (new BigDecimal("1.2686589").round(2))
assert (1.2686589).round(2) == 1.27
assert (1.2334695).round(2) == 1.23
Like this:
def f = 1.2334695;
println new DecimalFormat("#.##").format(f);
Or like this:
println f.round (new MathContext(3));
Output:
1.23
Reference: Formatting a Decimal Number
Groovy adds a round() method to the Double and Float classes, so:
(123.456789f).round(2) == 123.46f
Source: Rounding Numbers in Groovy
Probably, more Groovysh way would be to use this snippet (x as double).round(2) like this:
def a = 5.2355434
println "a = $a, a.class = ${a.getClass()}"
def b = (a as double).round(2)
println "b = $b, b.class = ${b.getClass()}"
Looking at #sjtai's and #cdeszaq's answers you don't need to get mixed up with mixin if you just define a method like this:
def bigDecimalRound(n,decimals){
return(n.setScale(decimals, BigDecimal.ROUND_HALF_UP))
}
It is the BigDecimal builtin method setScale that performs the rounding.
println(1.2334695.setScale(2, BigDecimal.ROUND_HALF_UP))
>> 1.23
It's worth noting also that setScale accepts negative arguments in order to round things to larger order of magnitude, i.e.
println(123.2334695.setScale(-1, BigDecimal.ROUND_HALF_UP))
>> 1.2E+2
Working from #sjtai's great answer, this is the Mixin I use for just about all my decimal rounding needs:
class Rounding {
public BigDecimal round(int decimalPlaces = 0, RoundingMode roundingMode = RoundingMode.HALF_EVEN) {
return setScale(decimalPlaces, roundingMode);
}
}
If rounds to an int by default, and uses an "even" rounding method (reducing statistical error by default is always a good thing), but it still allows the caller to easily override these.
as simple as this:
YOUR_NUMBER = 1.234567
((int) YOUR_NUMBER * 100)/100
note: this would cut off the extra decimal points; it doesn't round up.
For example:
def rd = 1.3425345352
sd = ((float)rd).round(3)
println sd
>> 1.343
This is surprisingly complex for Groovy. It's usually... groovier.
You need to create a MathContext object to do the rounding.
num = 9.59123331333g
// rounds to 2 places, rounding up by default
mc = new java.math.MathContext(2)
num.round(mc)
==> Result: 7.0
with help from
https://blogs.oracle.com/fadevrel/rounding-numbers-and-decimal-places-in-numerical-fields
https://docs.oracle.com/javase/7/docs/api/java/math/MathContext.html
https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#round(java.math.MathContext)
You can convert any number to float and then use the round() function as:
((float)1.2334695).round(2)

Convert from Price

Im attempting to Convert a Price (from an API (code below)).
public class Price
{
public Price();
public Price(double data);
public Price(double data, int decimalPadding);
}
What I would like to do is compare the price from this API to a Double. Simply trying to convert to Double isnt working as I would have hoped.
Double bar = 21.75;
Price price = new Price();
if (Convert.ToDouble(price) >= bar) {
//code
}
when I try something like this, I believe it says the value must be lower than infinity.
How can I convert this price so they can be compared?
Convert.ToDouble cannot magically convert a Price object to a double, unless Price implements IConvertible.
You would need a property in your price object that returns the double and compare that.
You could use an implicit operator to convert to double. This is as per the MSDN for "implicit" operator in C#.
E.g.
class Price
{
public static implicit operator double (Price d)
{
return d.data;
}
public static implicit operator Price (double d)
{
return new Price(d);
}
}
Alternatively, for your comparisons, implement IComparable<double> and IEquatable<double> on your Price class then use the CompareTo instead and/or another operator overload.

Converting a string to int in Groovy

I have a String that represents an integer value and would like to convert it to an int. Is there a groovy equivalent of Java's Integer.parseInt(String)?
Use the toInteger() method to convert a String to an Integer, e.g.
int value = "99".toInteger()
An alternative, which avoids using a deprecated method (see below) is
int value = "66" as Integer
If you need to check whether the String can be converted before performing the conversion, use
String number = "66"
if (number.isInteger()) {
int value = number as Integer
}
Deprecation Update
In recent versions of Groovy one of the toInteger() methods has been deprecated. The following is taken from org.codehaus.groovy.runtime.StringGroovyMethods in Groovy 2.4.4
/**
* Parse a CharSequence into an Integer
*
* #param self a CharSequence
* #return an Integer
* #since 1.8.2
*/
public static Integer toInteger(CharSequence self) {
return Integer.valueOf(self.toString().trim());
}
/**
* #deprecated Use the CharSequence version
* #see #toInteger(CharSequence)
*/
#Deprecated
public static Integer toInteger(String self) {
return toInteger((CharSequence) self);
}
You can force the non-deprecated version of the method to be called using something awful like:
int num = ((CharSequence) "66").toInteger()
Personally, I much prefer:
int num = 66 as Integer
Several ways to do it, this one's my favorite:
def number = '123' as int
As an addendum to Don's answer, not only does groovy add a .toInteger() method to Strings, it also adds toBigDecimal(), toBigInteger(), toBoolean(), toCharacter(), toDouble(), toFloat(), toList(), and toLong().
In the same vein, groovy also adds is* eqivalents to all of those that return true if the String in question can be parsed into the format in question.
The relevant GDK page is here.
I'm not sure if it was introduced in recent versions of groovy (initial answer is fairly old), but now you can use:
def num = mystring?.isInteger() ? mystring.toInteger() : null
or
def num = mystring?.isFloat() ? mystring.toFloat() : null
I recommend using floats or even doubles instead of integers in the case if the provided string is unreliable.
Well, Groovy accepts the Java form just fine. If you are asking if there is a Groovier way, there is a way to go to Integer.
Both are shown here:
String s = "99"
assert 99 == Integer.parseInt(s)
Integer i = s as Integer
assert 99 == i
also you can make static import
import static java.lang.Integer.parseInt as asInteger
and after this use
String s = "99"
asInteger(s)
toInteger() method is available in groovy, you could use that.
Several ways to achieve this. Examples are as below
a. return "22".toInteger()
b. if("22".isInteger()) return "22".toInteger()
c. return "22" as Integer()
d. return Integer.parseInt("22")
Hope this helps
Groovy Style conversion:
Integer num = '589' as Integer
If you have request parameter:
Integer age = params.int('age')
def str = "32"
int num = str as Integer
Here is the an other way. if you don't like exceptions.
def strnumber = "100"
def intValue = strnumber.isInteger() ? (strnumber as int) : null
The way to use should still be the toInteger(), because it is not really deprecated.
int value = '99'.toInteger()
The String version is deprecated, but the CharSequence is an Interface that a String implements. So, using a String is ok, because your code will still works even when the method will only work with CharSequence. Same goes for isInteger()
See this question for reference :
How to convert a String to CharSequence?
I commented, because the notion of deprecated on this method got me confuse and I want to avoid that for other people.
The Simpler Way Of Converting A String To Integer In Groovy Is As Follows...
String aa="25"
int i= aa.toInteger()
Now "i" Holds The Integer Value.

Resources