Dart - NumberFormat - dart

Is there a way with NumberFormat to display :
'15' if double value is 15.00
'15.50' if double value is 15.50
Thanks for your help.

Actually, I think it's easier to go with truncateToDouble() and toStringAsFixed() and not use NumberFormat at all:
n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2);
So for example:
main() {
double n1 = 15.00;
double n2 = 15.50;
print(format(n1));
print(format(n2));
}
String format(double n) {
return n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2);
}
Prints to console:
15
15.50

Edit: The solution posted by Martin seens to be a better one
I don't think this can be done directly. You'll most likely need something like this:
final f = new NumberFormat("###.00");
String format(num n) {
final s = f.format(n);
return s.endsWith('00') ? s.substring(0, s.length - 3) : s;
}

Not very easily. Interpreting what you want as printing zero decimal places if it's an integer value and precisely two if it's a float, you could do
var forInts = new NumberFormat();
var forFractions = new NumberFormat();
forFractions.minimumFractionDigits = 2;
forFractions.maximumFractionDigits = 2;
format(num n) =>
n == n.truncate() ? forInts.format(n) : forFractions.format(n);
print(format(15.50));
print(format(15.0));
But there's little advantage in using NumberFormat for this unless you want the result to print differently for different locales.

Maybe you don't want use NumberFormat:
class DoubleToString {
String format(double toFormat) {
return (toFormat * 10) % 10 != 0 ?
'$toFormat' :
'${toFormat.toInt()}';
}
}

A variant of double value formatting:
void main (){
final n1 = 15.00;
final n2 = 15.50;
print(format(n1));
print(format(n2));
}
String format(double n) {
final fraction = n - n.toInt();
if (fraction == 0.0) {
return n.toString();
}
var twoDigitFraction = (fraction * 100).truncateToDouble().toInt();
return '${n.toInt()}.$twoDigitFraction';
}

This will work.
main() {
double n1 = 15.00;
double n2 = 15.50;
print(_formatDecimal(n1));
print(_formatDecimal(n2));
}
_formatDecimal(double value) {
if (value % 1 == 0) return value.toStringAsFixed(0).toString();
return value.toString();
}
Output:
15
15.5

An alternate solution, working on the string output of NumberFormat:
final f = NumberFormat("###.00");
print(f.format(15.01).replaceAll('.00', ''));
print(f.format(15.00).replaceAll('.00', ''));

Here is a flexible function that nicely rounds and removes trailing zeros after the decimal point to resolve double's imperfections. This doesn't handle the strictly 0 or 2 decimal points scenario from the question, but rather is a more general formatting for double numbers that may be useful for others to consider.
The verbose value can be changed to fit precision needs.
void main() {
for (double i = 0; i < 10; i += 0.3) {
print(i);
print(_formatDouble(i));
}
}
//Creates nicely formatted number string without trailing decimal zeros.
String _formatDouble(double value) {
//this also rounds (so 0.8999999999999999 becomes '0.9000')
var verbose = value.toStringAsFixed(4);
var trimmed = verbose;
//trim all trailing 0's after the decimal point (and the decimal point if applicable)
for (var i = verbose.length - 1; i > 0; i--) {
if (trimmed[i] != '0' && trimmed[i] != '.' || !trimmed.contains('.')) {
break;
}
trimmed = trimmed.substring(0, i);
}
return trimmed;
}
prints output:
0
0
0.3
0.3
0.6
0.6
0.8999999999999999
0.9
1.2
1.2
1.5
1.5
1.8
1.8
2.1
2.1
2.4
2.4
2.6999999999999997
2.7
2.9999999999999996
3
3.2999999999999994
3.3
3.599999999999999
3.6
3.899999999999999
3.9
4.199999999999999
4.2
4.499999999999999
4.5
4.799999999999999
4.8
5.099999999999999
5.1
5.399999999999999
5.4
5.699999999999998
5.7
5.999999999999998
6
6.299999999999998
6.3
6.599999999999998
6.6
6.899999999999998
6.9
7.1999999999999975
7.2
7.499999999999997
7.5
7.799999999999997
7.8
8.099999999999998
8.1
8.399999999999999
8.4
8.7
8.7
9
9
9.3
9.3
9.600000000000001
9.6
9.900000000000002
9.9

Related

Establish ranges in array of Doubles

I am looking to establish the various ranges that may exist in an array of Double values. This is best explained with an example. Say I have the following set of numbers:
[1.5, 1.6, 1.7, 1.8, 2.9, 3.0, 3.1, 4.0]
I would like to be able to determine, with a given granularity (in this case 0.1), that the ranges in this set are:
1.5-1.8, 2.9-3.1, 4.0
Any ideas?
Example data set for granularity of 0.01:
[407.46, 407.47, 407.48, 407.49, 407.5, 407.51, 407.52, 407.53, 407.54, 407.55, 407.56, 407.57, 407.58, 407.59, 407.6, 407.61, 407.62, 407.63, 407.64, 407.65, 407.66, 407.67, 407.68, 407.69, 407.7, 407.71, 407.72, 407.73, 407.74, 407.75, 407.76, 407.77, 407.78, 407.79, 407.8, 407.81, 407.82, 407.83, 407.84, 407.85, 407.86, 407.87, 407.88, 407.89, 407.9, 407.91, 440.27, 440.28, 440.29, 440.3, 440.31, 440.32, 440.33, 440.34, 440.35, 440.36, 440.37, 440.38, 440.39, 440.4, 440.41, 440.42, 440.43, 440.44, 440.45, 440.46, 440.47, 440.48, 440.49, 440.5, 440.51, 440.52, 440.53, 440.54, 440.55, 440.56, 440.57, 440.58, 440.59, 440.6, 440.61, 440.62, 440.63, 440.64, 440.65, 440.66, 440.67, 440.68, 440.69, 440.7, 440.71, 440.72, 440.73, 440.74]
A longer and simpler implementation:
func getRanges(from values: [Double], with granularity: Double) -> [ClosedRange<Double>] {
if values.count == 1 {
return [values[0]...values[0]]
}
var ranges = [ClosedRange<Double>]()
var lowerBound: Double = 0
var upperBound: Double = 0
for (i, value) in values.enumerated() {
if i == 0 {
lowerBound = value
upperBound = value
continue
}
let multiplier: Double = (1 / granularity).rounded()
let multipliedGranularity = granularity * multiplier
if (value * multiplier - (upperBound * multiplier + multipliedGranularity)).isLess(than: multipliedGranularity) {
upperBound = value
} else {
ranges.append(lowerBound...upperBound)
lowerBound = value
upperBound = value
}
if i == values.count - 1 {
ranges.append(lowerBound...upperBound)
}
}
return ranges
}
Using your sample the result is:
ClosedRange(407.46...407.91)
ClosedRange(440.27...440.74)
This code works even with smaller granularities. For example, with granularity 0.0000000001 and the following values:
[407.9999999991, 407.9999999992, 407.9999999994, 407.9999999995]
result:
ClosedRange(407.9999999991...407.9999999992)
ClosedRange(407.9999999994...407.9999999995)

How to Round numbers at 0.6, 1,6, 2,6,...?

I want this to be true for all numbers. I don't want to type this for all numbers of course.
if (overs == 0.6) {
overs = 1.0;
}
I want that if for example 1.6, is reached, it should be converted to 2. I want this to be true for all numbers.
Further Clarification: I don't want it to round at For eg 0.5, i want it to round at 0.6
One Liner
double roundAt6(double n) => (n - n.floor()) > 0.5 ? n.ceil() : n;
Detailed
void main() {
final double overs = 5.6;
print('result: ${roundAt6(overs)}');
}
double roundAt6(double n) {
final double decimalPart = n - n.floor();
print('decimal part: $decimalPart');
final bool didExceed = decimalPart > 0.5;
print('didExceed: $didExceed');
return didExceed ? n.ceil() : n;
}
Maybe ceil()
Returns the least integer no smaller than this.
Example
overs = overs.ceil()
Use round() method.
Returns the integer closest to this.
Example
overs = overs.round()
Insights porvided by #Amsakanna helped me solve the problem. I am posting the exact solution here:
if ((overs - overs.floor()) > 0.55)
{
overs = overs - (overs - overs.floor()) + 1;
}

How to do BigInt arithmetic in Dart 2.x, specifically division?

Dart documentation says that BigInt division returns a value of type 'double'. This is a problem. To illustrate, here are two implementations of an algorithm involving division. The first is in Kotlin, the second is in Dart. The Dart version runs accurately for small numbers but loses precision for larger numbers.
Kotlin
import java.math.BigInteger
fun height(n: BigInteger, m: BigInteger): BigInteger {
var m1 = m
var s = BigInteger("1")
var b = BigInteger("1")
var ans = BigInteger("0")
var i = 0
while (i < n.toInt()) {
s *= m1--
s /= b++
ans += s
i++
}
return ans
}
Dart
BigInt height(int n, int m) {
var m1 = m; // new BigInt.from(m);
var s = 1.0; // new BigInt.from(1);
var b = 1.0; // new BigInt.from(1);
var ans = new BigInt.from(0);
var i = 0;
while (i < n) {
s *= m1--;
s /= b++;
ans += BigInt.from(s);
i++;
}
return ans;
}
As you can see from the commented out Dart code, I have tried various ways to use BigInt.
Here is an example input with answer. The erroneous Dart answer is given below.
height(13, 550),
equals(BigInt.parse('60113767426276772744951355')));
The erroneous Dart answer is --> 60113767426276764034189615
Can someone show me the best way to do the job in Dart v2.x?
The following code works.
BigInt height(int n, int m) {
var m1 = new BigInt.from(m);
var s = new BigInt.from(1);
var b = new BigInt.from(1);
var ans = new BigInt.from(0);
var i = 0;
while (i < n) {
s *= m1;
m1 -= new BigInt.from(1);
s = s ~/ b;
b += new BigInt.from(1);
ans += s;
i++;
}
return ans;
}
Changes:
x++ and x-- are equivalent to x = x + 1 and x = x - 1 but BigInt.+ and BigInt.- only accept BigInt values... so there's a compiler error.
BigInt./ returns a double and this is not what you want here. You need to use the BigInt.~/ operator instead.

Shorthand comparison ends up being too long to understand

There's a "Clamp" function from a library of Ray Wenderlich class's - SKTUtils to be exact. This clamp function is written in shorthand but in a way that I can't seem to understand. This clamps purpose is to limit a position to an area - the games "camera" follows the _player.position, while making sure the the player never sees the nothingness outside the game map. Here's the function:
CGFloat Clamp(CGFloat value, CGFloat min, CGFloat max)
{
return value < min ? min : value > max ? max : value;
}
Here is the method it's used in, which the method it self gets used inside 'didFinishUpdate' method:
-(CGPoint)pointToCenterViewOn:(CGPoint)centerOn
{
CGFloat x = Clamp(centerOn.x, self.size.width/2, _backgroundLayer.layerSize.width - self.size.width/2); //Value, Min, Max.
CGFloat y = Clamp(centerOn.y, self.size.height/2, _backgroundLayer.layerSize.height - self.size.height/2);
return CGPointMake(-x, -y);
}
-(void)didFinishUpdate
{
_worldNode.position = [self centerViewOnPoint:_player.position];
}
Can someone explain this?
value < min ? min : value > max ? max : value
I could only partially understand the shorthands beginning:
if (value < min)
{
value = min;
}
else if (value > min)
{
value > max??????
}
Here is the explanation of value < min ? min : value > max ? max : value
if (value < min)
{
return min
}
else
{
if (value > max)
{
return max
}
else
{
return value
}
}
Operator precedence is partially involved here. This would be made a lot nicer with some parentheses to aid reading. The comparison operators bind tighter than the ternary conditional, so you have:
(value < min) ? min : ((value > max) ? max : value)
From there it's just evaluated left-to-right. The only tricky bit is that the else branch of the first conditional operator is itself another conditional operator. This would be the equivalent of an else if were you to expand it. The else branch of the second conditional is thus the else for the whole expression.
To convert this to if statements, then, you would do:
CGFloat retVal;
if( value < min ){
retVal = min;
}
else if( value > max ){
retVal = max;
}
else {
retVal = value;
}
return retVal;
You might also prefer this way to clamp a value:
MAX(min_limit, MIN(value, max_limit))
which uses the MAX and MIN macros to evaluate to the lower of max_limit or value and the higher of that or min_limit, producing a result in the range between min_limit and max_limit (inclusive). The effect is the same; I think that's easier to read.

Program doesn't work without an initial value

The program works fine with var dig = 0 and it doesn't work with var dig:Int I get an error: Variable "dig" used before being initialized Could you explain me why?
func myFunc(a:Int, b:Int) {
var c = a / b
var o = a % b
var v = 0
var dig = 0
if o != 0 {println("\(a)/\(b) = \(c) и \(o)/\(b)")}
else {println("\(a)/\(b) = \(c)")}
if a > b {
v = b
}
else {
v = a
}
for var i = 1; i <= v; ++i {
if a % i == 0 && b % i == 0 {dig = i}
}
println("\(dig) -  greatest common denominator of \(a) and \(b)")
}
myFunc(27,81)
The only place you set the value of dig is inside of an if statement that is inside of a for loop. The Swift compiler does not know if the body of the for loop will be executed, and it doesn't know if the if statement will ever be true, so it has to assume that there is a path in which dig is not initialized.
Consider this simpler example:
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
}
if a < b {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
This example also gives the same error, because Swift considers each if separately. It is obvious to us that a is either greater than or equal to b or it is less than b, but Swift doesn't go that far in evaluating the situation. It just considers that each if may not be true, and dig is only set inside of ifs, so it is possible (as far as Swift is concerned) that dig may not be set.
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
} else {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
If you change the second condition to an else, Swift is then happy because it can reason that the if must be true or false and dig is set in each path, so it will certainly have a value before the println statement.
The compiler does not know mathematics good enough to
recognize that the statement
if a % i == 0 && b % i == 0 {dig = i}
is actually executed at least once (for i == 1). Therefore
the compiler assumes that dig might be undefined at
println("\(dig) - greatest common denominator of \(a) and \(b)")
Assigning an initial value in
var dig = 0
is the correct solution.
Btw., the Euclidean Algorithm is a much more effective method to
compute the greatest common divisor, see for example
http://rosettacode.org/wiki/Greatest_common_divisor#Swift.

Resources