I'm writing an application that uses AVFoundation and CMTime. I have logged the values of my CMTime instances created using CMTimeMake(). This value seems to be rounded to the nearest integer. I need a CMTime instance with a precise value, without rounding.
I have seen the rounding constants in the CMTime reference:
enum {
kCMTimeRoundingMethod_RoundHalfAwayFromZero = 1,
kCMTimeRoundingMethod_RoundTowardZero = 2,
kCMTimeRoundingMethod_RoundAwayFromZero = 3,
kCMTimeRoundingMethod_QuickTime = 4,
kCMTimeRoundingMethod_RoundTowardPositiveInfinity = 5,
kCMTimeRoundingMethod_RoundTowardNegativeInfinity = 6,
kCMTimeRoundingMethod_Default = kCMTimeRoundingMethod_RoundHalfAwayFromZero
};
There aren't any example of how I can control which of these strategies is applied to a CMTime instance? Or, if this isn't the right way, how can I extract a precise value from a CMTime instance?
Edit:
I have found and tested CMTIME_HAS_BEEN_ROUNDED(). I passed my CMTime instance to this function and it returns No (indicating that the value has not been rounded). So why am I losing precision?
If you read the documentation for CMTime you will see that it stores time as a rational number using a numerator and denominator. The numerator is int64_t while the denominator is int32_t.
The numerator specifies how many "ticks" have passed, and the denominator specifies how many "ticks" per second.
So 0.5 seconds can be stored as:
100/200: 100 ticks, 200 ticks per second
500/1000: 500 ticks, 1000 ticks per second
8/16, 8 ticks, 16 ticks per second
And so forth. The way you have done it, using
CMTimeMake([[Array objectAtIndex:i]floatValue], 1);
Is saying "there is one tick per second", and since the numerator is an integer, the float value is truncated so only the 1 is stored. Therefore you are specifying time as: 1/1, one tick has elapsed, one tick per second, so you are actually storing exactly 1 second.
To fix this, it depends on what you want to do and whether you care about the timescale. Apple recommends a timescale of 600, but if you don't care, you can just do this:
CMTimeMake([[Array objectAtIndex:i]floatValue]*1000, 1000);
That sets timescale to 1000, so 1000 ticks per second, so one millisecond per tick. It also converts the time in seconds to milliseconds. Note that it truncates the 4th digit, so if you had 1.2345 you just get 1.234 not 1.235. If that matters to you, see roundf.
CMTimeMake([[Array objectAtIndex:i]floatValue]*1000, 1000);
This helped me to get exact time in milliseconds. Cheers.
Related
I have two variables, a speed and a minimum. The speed gets compared to the minimum to see if the speed should continue decreasing. For some reason, even when the speed is equal to the minimum, it continues to decrease the speed.
var wallSpeed : CGFloat!
var wallSpeedMin : CGFloat!
var wallSpeedChange : CGFloat!
override init(){
wallSpeed = 0.0035
wallSpeedMin = 0.0034
wallSpeedChange = 0.0001
}
The speed minimum is close to the speed for testing purposes.
if wallSpeed > wallSpeedMin
{
print("Wall speed has been increased")
wallSpeed = wallSpeed - wallSpeedChange
print("New speed is \(wallSpeed!)")
}else
{
print("Player moved up screen")
//Move player up instead
playerNode.position.y = playerNode.position.y + 5
print("Players Y value is \(playerNode.position.y)")
}
It never hits the else statement, even though the wall speed is equal to the wall speed minimum after the first decrease.
Do I have my if statement set up incorrectly? What is causing this behavior?
Floating point math does not work like you're expecting it to. Check Is floating point math broken?
You can't compare floating point numbers like this way...
Since the way of the floating point number represented we can't simply do some math on them....
when we use integers they are represented directly in binary format, and you can do any arithmetic calculation on them, while floating point numbers are 32 bits container following the IEEE 754 standard divided in three sections :
1 bit S for the sign
8 bits for the exponent
23 bits for the mantissa
For more information Comparing Floating Point Numbers and Floating Point in Swift
I try to find the steps between a min and a max value with a given step-size, using swift 2.1.
So we have a min and a max value, both of type Double. The step-size is a Double too. If min is 0.0 and max 0.5 with steps of 0.1, the result is 6, obviously.
But if I start with -0.1 as the minimum value, the result is 6 too. But should be 7, agree?
Here is my Playground example:
let min:Double = -0.1
let max:Double = 0.5
let step:Double = 0.1
var steps: Int {
return Int((max - min) / step) + 1
}
print("steps: \(steps)") // returns "steps: 6", but should be 7
The result is 6.99999999 if we use a Double for the steps variable. But this loss of precision only occurs when our min value is negative.
Do you know a workaround? I just don't want to round() each time I calculate with Doubles.
When you use Int() it forces truncation of your number, which always rounds towards zero. So, 6.9999 becomes 6 rather than 7, because it's closer to zero. If you use round() first it should help:
var steps: Int {
return Int(round((max - min) / step) + 1.0)
}
That's always not a good idea to calculate integral steps based on floating point ranges, you'll always encounter issues, and you won't be able to do much.
Instead I recommend to build your logic on integral steps, and calculate double values based on integral values (not vice versa as you do). I.e. you don't calculate integral step based on range, but you set your integral number of steps and calculate your double step.
I have 1000+ row Sine Wave data which changes with time and I want to visualize it with Processing language. My aim is to create an animation which will draw a Sine Wave with time starting from the middle of the rectangular [height/2]. I also want to show only the 1 second periods of that wave. I mean after 1 second, first coordinate should dissappear, and so forth.
How can I achieve that ?
Thanks
Sample Data :
TIME X Y
0.1333 0 0
0.2666 0.1 0.0999983333
0.3999 0.2 0.1999866669
0.5332 0.3 0.299955002
0.6665 0.4 0.3998933419
0.7998 0.5 0.4997916927
0.9331 0.6 0.5996400648
1.0664 0.7 0.6994284734
The way you'd achieve that is to split this project into tasks:
load & parse data
update time and render data
To make sure part 1 goes smoothly it's probably best to make sure your data is easy to parse first. The sample data looks like a table/spreadsheet, but it's not formatted with a standard separator(e.g. comma or tab). You can fiddle things when you parse, but I recommend using clean data first, for example, if you plan on using space as a separator:
TIME X Y
0.1333 0.0 0
0.2666 0.1 0.0999983333
0.3999 0.2 0.1999866669
0.5332 0.3 0.299955002
0.6665 0.4 0.3998933419
0.7998 0.5 0.4997916927
0.9331 0.6 0.5996400648
1.0664 0.7 0.6994284734
Once that's done, you can use loadStrings() to load the data and split() to break a row into 3 elements which can be converted from string to float.
Once you've got value to use, you can store them. You can either create three arrays, each holding a field from the loaded data(one for all the X values, one for all the Y values and one for all the time values) or you can cheat and use a single array of PVector objects. Although PVector is meant for 3D math/linear algebra, you have 2D coordinates, so you can store time as 3rd 'dimension'/component.
Part two revolves mostly around updating based on time, and this is where millis() comes in handy. You can check the amount of time passed between updates and if it's greater than a certain (delay) value, it's time for another update (of the frame/data row index).
The last part you need to worry about is rendering the data on screen. Luckily in your sample data the coordinates are normalized(between 0.0 and 1.0) which makes easy to map to the sketch dimensions(by using simple multiplication). Otherwise the map() function comes in handy.
Here's a sketch to illustrate the above, data.csv is a text file containing the formatted sample data from above:
PVector[] frames;//keep track of the frame data(position(x,y) and time(store in PVector's z property))
int currentFrame = 0,totalFrames;//keep track of the current frame and total frames from the csv
int now, delay = 1000;//keep track of time and a delay to update frames
void setup(){
//handle data
String[] rows = loadStrings("data.csv");//load data
totalFrames = rows.length-1;//get total number of lines (-1 = sans the header)
frames = new PVector[totalFrames];//initialize/allocate frame data array
for(int i = 1 ; i <= totalFrames; i++){//start parsing data(from 1, skip header)
String[] frame = rows[i].split(" ");//chop each row into 3 strings(time,x,y)
frames[i-1] = new PVector(float(frame[1]),float(frame[2]),float(frame[0]));//parse each row(not i-1 to get back to 0 index) and how the PVector's initialized 1,2,0 (x,y,time)
}
now = millis();//initialize this to keep track of time
//render setup, up to you
size(400,400);smooth();fill(0);strokeWeight(15);
}
void draw(){
//update
if(millis() - now >= delay){//if the amount of time between the current millis() and the last time we updated is greater than the delay (i.e. every 'delay' ms)
currentFrame++;//update the frame index
if(currentFrame >= totalFrames) currentFrame = 0;//reset to 0 if we reached the end
now = millis();//finally update our timer/stop-watch variable
}
PVector frame = frames[currentFrame];//get the data for the current frame
//render
background(255);
point(frame.x * width,frame.y * height);//draw
text("frame index: " + currentFrame + " data: " + frame,mouseX,mouseY);
}
There are a couple of extra notes needed:
You mentioned moving to the next coordinate after 1 second. From what I can see in your sample data there are 8 updates per second, so 1000/8 would probably work better. It's up to you how you handle timing though.
I assume your full set includes data for a sine wave movement. I've mapped to the full coordinates, but in the render part of the draw() loop you can map however you like(e.g. including a height/2 offset, etc.). Also if you're not familiar with sine waves, have a look at these Processing resources: Daniel Shiffman's SineWave sample, Ira Greenberg's trig tutorial.
I am trying to calculate pace (min/mi) and format it as mmmm:ss.
So far I calculate my pace into a float by taking 60 and dividing it by my average speed. At an average speed of 76mph, my average pace is displayed as 0.79. I want to format it so that it converts my 0.79 minutes to mmmm:ss (thus showing my average pace as 0000:47). How can I do this?
double milesPerHour = 76.0;
int secondsPerMile = (int)round(3600.0 / milesPerHour);
NSString *paceString = [NSString stringWithFormat:#"%04d:%02d", secondsPerMile / 60, secondsPerMile % 60];
Not sure if I get your question right, but this is pretty much just math.
You can get the minutes by rounding your value (0.79 in this case) down and you can get seconds by taking your value, subtracting the minutes from it and multiplying that by 60.
So if you'd need 2.35 minutes for a mile, you'd have 2 minutes and 0.35*60 = 21 seconds.
I am developing an app and want to round off values
i.e if the output is 4.8 I want to display 4.8
while if the output is 4.0 , I want to display 4
Also, it would be great if I could precisely round values : as in if value is 4.34 then round to 4.3 while if its 4.37 then round it to 4.4
One way to round floating point values is to just add 0.5 and then truncate the value.
double valueToRound = GetTheValueFromSomewhere();
double roundedValue = (double)((int)(valueToRound + 0.5));
This will round 1.4 down to 1.0 and 1.5 up to 2.0 for example. To round to other decimal places as you mentioned, simply multiply the initial value by 10, or 100, etc. use the same sort of code, and then divide the result by the same number and you'll get the same result at whatever decimal place you want.
Here's an example for rounding at an arbitrary precision.
double valueToRound = GetTheValueFromSomewhere();
int decimalPrecisionAtWhichToRound = 0;
double scale = 10^decimalPrecisionAtWhichToRound;
double tmp = valueToRound * scale;
tmp = (double)((int)(tmp + 0.5));
double roundedValue = tmp / scale;
So, if decimalPrecisionAtWhichToRound is set to 0 as in the above it'll round to the nearest whole integer. 1.4 will round to 1.0. 1.5 will round to 2.0.
If you set decimalPrecisionAtWhichToRound to 1, it would round to the nearest tenth. 1.45 would round to 1.5 and 1.43 would round to 1.4.
You need to first understand how to do rounding on paper, without someone showing you the code to do it. Write down some numbers and figure out how to round them.
To round to a specific decimal position you add half the value of that position and then truncate. Ie, 1.67 + 0.05 = 1.72 then truncate to 1.7.
But there are two tricky things in programming that aren't there when you do it on paper:
Knowing how to truncate -- There are several ways to do it while programming, but they're non-trivial.
Dealing with the fact that floating-point numbers are imprecise. Ie, there is no exact representation of, say, 1.7, but rather the two closest numbers are apt to be something like 1.69998 and 1.700001
For truncating the trick of multiplying the number by the appropriate power of 10 to produce an integer works pretty well. Eg, (1.67 + 0.05) * 10 = 17.2, then convert to int to get 17, then convert back to float and divide by 10 to get 1.7 (more or less). Or (if you're printing or displaying the value) just format the integer number with the decimal point inserted. (By formatting the integer value you don't have to deal with the problem of imprecise floating point representations.)
If you want to suppress trailing zeros it gets a bit trickier and you probably have to actually write some code -- format the number, then scan backwards and take off any trailing zeros up to the decimal point. (And take the decimal point too, if you wish.)
float number=17.125;
NSNumberFormatter *format = [[NSNumberFormatter alloc]init];
[format setNumberStyle:NSNumberFormatterDecimalStyle];
[format setRoundingMode:NSNumberFormatterRoundHalfUp];
[format setMaximumFractionDigits:2];
NSString *temp = [format stringFromNumber:[NSNumber numberWithFloat:number]];
NSLog(#"%#",temp);
double myNumber = 7.99;
NSString *formattedNumber = [NSString stringWithFormat:#"%.*f",
fmod(round(myNumber * 10), 10) ? 1 : 0, myNumber];