Establish ranges in array of Doubles - ios

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)

Related

Dart - Overflow Safe Summation of List

In Dart, is there a simple way to check whether the sum of a list will produce a 'real' value (a value that doesn't overflow or underflow)?
Examples:
overflowSafeSum([0,1,2]) //3
overflowSafeSum([1,9223372036854775807]) //Over
overflowSafeSum([-1,-9223372036854775808]) //Under
I'm new to dart, this is the best I got right now:
import 'dart:math' show pow;
enum Overflow {
over,
under,
}
void main() {
//idea: Iterate through the elements of a list and add them,
//each time the sum overflows: increase overflowCounter by 1
//each time the sum underflows: decrease overflowCounter by 1
//if all the elements have been added and the overflowCounter == 0, the sum must be real
overflowSafeSum(List<int> userList) {
var sum = 0, overflowCounter = 0;
for (int index = 0, nextTerm;
index < userList.length;
index++, sum += nextTerm) {
nextTerm = userList[index];
if (sum.sign != nextTerm.sign) {
continue; //adding a postive and negative can't overflow or underflow
} else if (sum >= 0 && nextTerm >= 0) {
if ((sum + nextTerm) < 0) overflowCounter++;
} else {
if ((sum + nextTerm) >= 0) overflowCounter--;
}
}
if (overflowCounter == 0) {
return sum;
} else if (overflowCounter > 0) {
return Overflow.over;
} else {
return Overflow.under;
}
}
var myList = [1,0,(pow(2,63)-1).toInt()];
print(overflowSafeSum(myList)); //Overflow.over
}
(To be pedantic: "underflow" is not negative overflow. Overflow occurs when the magnitude of a number is too large to be represented, regardless of sign. Underflow is an issue with floating-point operations where the magnitude of a number is too small (too close to 0) to be represented.)
You can't generally detect overflow with Dart ints since Dart for the web is transpiled to JavaScript, where ints are backed by JavaScript numbers (IEEE-754 double-precision floating-point values). If you instead use Int32 or Int64 from package:fixnum (or if you restrict yourself to the Dart VM), then you could make a helper function like:
class OverflowException implements Exception {
OverflowException({this.positive = true});
bool positive;
}
Int64 checkedAdd(Int64 a, Int64 b) {
var sum = a + b;
if (a > 0 && b > 0 && sum < 0) {
throw OverflowException(positive: true);
}
if (a < 0 && b < 0 && sum > 0) {
throw OverflowException(positive: false);
}
return sum;
}
From there, you could trivially add a function that calls it in a loop:
Int64 overflowSafeSum(Iterable<int> numbers) {
var sum = Int64(0);
for (var number in numbers) {
sum = checkedAdd(sum, Int32(number));
}
return sum;
}
or if you prefer using Iterable.fold:
Int64 overflowSafeSum(Iterable<int> numbers) =>
numbers.fold<Int64>(Int64(0), (sum, i) => checkedAdd(sum, Int64(i)));

How to interpret YOLOv4 output

Im trying to interpret the YOLOv4 output using TensorFlowLite on the iOS. I have read a little about the concept of cells and anchors used in the output tensor, and I would like to implement the parser for it. Output of my model consists of 2 tensors:
float32[1,13,13,255]
float32[1,26,26,255]
First thing Im wondering about is what is in the second output? From what I have read the first one should contain all the information. Is the second one just a more detailed result or something else?
Ok, but let's start with the first output. I have written a simple function that should extract all cells and then all anchors data from these cells. This is how it looks:
let output0 = try localModel.output(at: 0)
guard let output0Floats = [Float](bytes: output0.data) else { return nil }
let numberOfCells = 13
let numberOfAnchors = 3
let numberOfClasses = 80
let anchorSize = (numberOfClasses + 5)
func cellAt(x: Int, y: Int) -> [Float] {
let cellSize = anchorSize * numberOfAnchors
let position = (y * numberOfCells + x) * cellSize
return [Float](output0Floats[position..<position + cellSize])
}
func anchors(in cell: [Float]) -> [[Float]] {
(0..<numberOfAnchors).map { [Float](cell[$0 * anchorSize..<$0 * anchorSize + anchorSize]) }
}
for y in 0..<numberOfCells {
for x in 0..<numberOfCells {
let cell = cellAt(x: x, y: y)
print("Cell: \(x),\(y) contains anchors:")
print(anchors(in: cell))
}
}
...
private extension Array {
init?(bytes: Data) {
guard bytes.count % MemoryLayout<Element>.stride == 0 else { return nil }
self = bytes.withUnsafeBytes { .init($0.bindMemory(to: Element.self)) }
}
}
And this is the example result I'm getting for a single cell:
Cell: 7,12 contains anchors:
[[0.693655, -1.1966848, -0.007975042, -0.3327814, -9.583811, 0.3976263, -6.0192285, -6.329881, -5.8644676, -10.2914715, -9.632221, -8.071436, -6.399925, -5.240812, -8.791572, -5.6437893, -9.8603115, -10.492198, -1.9372412, -7.0640965, -2.6936512, -5.112247, -7.131972, -7.1825066, -7.4413238, -10.401382, -7.5643044, -8.608834, -8.239082, -6.799241, -8.035741, -5.7502255, -8.881622, -7.3571744, -9.315964, -7.925786, -7.7857537, -4.8930154, -8.529579, -7.633353, -8.817726, -7.47082, -8.291334, -4.683982, -4.170734, -6.193165, -7.8437185, -9.854808, -9.490823, -8.272433, -8.434413, -7.765057, -7.149798, -11.194118, -6.5116143, -11.112444, -9.999684, -10.689343, -9.942104, -9.520727, -7.440444, -2.531265, -3.7234814, -7.5839844, -4.550161, -3.031804, -4.616852, -8.832014, -6.0279136, -9.482858, -6.750441, -8.450063, -10.222086, -7.6301804, -7.559189, -10.234117, -6.999834, -7.1350074, -5.308107, -6.2450233, -8.8833885, -9.381562, -3.8812854, -8.868278, -9.988986], [0.4351927, -1.3958519, 0.46428338, -0.39240548, -8.170114, 0.7084342, -7.709829, -5.9856057, -6.808081, -10.644019, -9.912677, -7.3293757, -7.548369, -5.533275, -10.072926, -7.316476, -9.945337, -11.118561, -3.2463353, -10.561513, -5.067392, -7.312641, -8.729989, -9.5539055, -7.58917, -9.886164, -6.5404315, -8.553915, -9.023286, -9.580754, -6.7592535, -8.380334, -8.182065, -7.2239976, -9.276712, -7.5086412, -7.2454534, -7.139829, -8.614485, -7.8158274, -9.850543, -9.123642, -6.8081083, -6.936388, -7.997142, -8.845028, -11.322939, -10.713314, -9.629859, -10.820017, -10.480835, -9.071951, -7.9244685, -12.562474, -7.1654305, -13.456438, -10.116255, -12.255847, -11.530319, -10.3949375, -10.665162, -5.6975913, -4.050809, -10.665826, -2.638548, -3.5531735, -7.0320325, -10.047072, -7.678191, -10.290669, -7.438999, -7.531754, -9.817409, -8.428637, -9.502961, -10.955662, -8.6340065, -5.0168147, -8.593948, -9.412493, -10.816083, -10.903126, -8.81499, -10.449745, -9.069517], [0.025469145, -1.7808459, -0.18256505, -0.70104045, -10.450736, -0.67288893, -5.771856, -5.448979, -6.4159226, -8.777289, -7.960696, -5.3555217, -4.798117, -2.8378687, -7.9489646, -8.255625, -8.968552, -8.036578, -2.46956, -8.458385, -4.8979797, -6.5746903, -7.2408285, -8.574903, -6.8356185, -6.4320874, -6.037178, -7.56021, -7.275848, -8.808907, -3.9019513, -8.835796, -6.360187, -6.5461373, -7.1117754, -6.6027184, -7.280362, -7.1671834, -7.292713, -7.1488175, -7.1398635, -8.180893, -5.797153, -6.3417816, -6.9332256, -8.371075, -9.2042055, -8.602686, -8.072069, -8.1690035, -8.0164175, -6.61691, -6.3536263, -9.318304, -4.5542707, -10.049933, -7.8087454, -9.497473, -9.07455, -8.406244, -7.078502, -5.5775504, -2.3586287, -8.409487, -1.6716739, -3.8225765, -6.9020715, -6.6682305, -5.784493, -8.40492, -7.2747784, -6.392035, -6.4958863, -7.629692, -7.4995623, -8.4432125, -6.7565637, -3.113231, -7.3596015, -8.573539, -8.829562, -8.523581, -8.571439, -8.087017, -7.958835]]
So single anchor looks like this:
[0.693655, -1.1966848, -0.007975042, -0.3327814, -9.583811, 0.3976263, -6.0192285, -6.329881, -5.8644676, -10.2914715, -9.632221, -8.071436, -6.399925, -5.240812, -8.791572, -5.6437893, -9.8603115, -10.492198, -1.9372412, -7.0640965, -2.6936512, -5.112247, -7.131972, -7.1825066, -7.4413238, -10.401382, -7.5643044, -8.608834, -8.239082, -6.799241, -8.035741, -5.7502255, -8.881622, -7.3571744, -9.315964, -7.925786, -7.7857537, -4.8930154, -8.529579, -7.633353, -8.817726, -7.47082, -8.291334, -4.683982, -4.170734, -6.193165, -7.8437185, -9.854808, -9.490823, -8.272433, -8.434413, -7.765057, -7.149798, -11.194118, -6.5116143, -11.112444, -9.999684, -10.689343, -9.942104, -9.520727, -7.440444, -2.531265, -3.7234814, -7.5839844, -4.550161, -3.031804, -4.616852, -8.832014, -6.0279136, -9.482858, -6.750441, -8.450063, -10.222086, -7.6301804, -7.559189, -10.234117, -6.999834, -7.1350074, -5.308107, -6.2450233, -8.8833885, -9.381562, -3.8812854, -8.868278, -9.988986]
Now I can't understand these numbers. From what I read, first 5 numbers should be:
Confidence, BBoxX, BBoxY, BBoxWidth, BBoxHeight
and the rest of the values are probabilities of each class in a labelMap.
But these numbers look totally incorrect to me. Shouldn't Confidence be between 0 and 1? And probabilities shouldn't be between 0 a 1? What can I be doing wrong that I'm getting these results? The code I'm using before parsing these results is well tested with other types of tflite files, and it should be fine. Can this be due to the incorrect imageMean and imageStd used in the input pixel buffer preparing? I'm not sure which values were used to build this model, so Im using 127.5 for both of these values.

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;
}

Dart - NumberFormat

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

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.

Resources