Is een delta T van 0 mogelijk met epoch tijd?

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • ikt
  • Registratie: Juli 2008
  • Laatst online: 00:02
Hoi,

ik heb een stukje code waar ik niet helemaal zeker van ben of dit vlekkeloos verloopt in alle mogelijkheden. Het is C++ en ik probeer hier een acceleratievector te berekenen van een game-object. Het gaat op zich goed, maar kan dit fout gaan?

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vector3 VehicleData::getAccelerationVectors(Vector3 velocities) {
    long long time = std::chrono::system_clock::now().time_since_epoch().count();
    Vector3 result;
    result.x = (velocities.x - prevVelocities.x)*1000000.0f / (time - prevTime);
    result.y = (velocities.y - prevVelocities.y)*1000000.0f / (time - prevTime);
    result.z = (velocities.z - prevVelocities.z)*1000000.0f / (time - prevTime);
    prevTime = time;
    prevVelocities = velocities;
    
    samples[averageIndex] = result;
    averageIndex = (averageIndex + 1) % (SAMPLES - 1);

    return result;
}


Het zit 'm in
code:
1
std::chrono::system_clock::now().time_since_epoch().count();
en
code:
1
time - prevTime
. Kan dit 0 zijn in normale omstandigheden? In het script-loopje wordt getAccelerationVectors() maar 1x per loop aangeroepen, dus dit zou tenminste iets uit elkaar moeten liggen. Kan het toch ooit voorkomen dat deze twee tijden gelijk zijn? Zo ja, hoe lomp is het dan om dit erbij te zetten? :+

Voor de deling:
code:
1
2
3
if (time == prevTime) {
    prevTime = time - 1;
}

Beste antwoord (via ikt op 01-06-2016 20:51)


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

ikt schreef op dinsdag 31 mei 2016 @ 23:54:
Het gaat op zich goed, maar kan dit fout gaan?
Ja. std::chrono::system_clock is niet gegarandeerd monotinically increasing. Als iemand de tijd aanpast (zoals een NTP service) dan reflecteert dat terug in de huidige tijd. Je bent ook helemaal niet geïnteresseerd in de huidige tijd, maar gewoon in een delta. Daar is std::chrono::steady_clock voor.

Meer specifieker ingaand op je vraag, je zult altijd rekening moeten houden met het feit dat de tijd tussen 2 calls niet groot genoeg is om dat terug te zien in het antwoord. Al zal dat in een typische gameloop op 60+ fps redelijk zeldzaam zijn. Bij mij (VC++ 2015 op Win10) is std::chrono::steady_clock::period 1ns.
Verwijderd schreef op woensdag 01 juni 2016 @ 00:57:
En stop die *1000000.0f / (time - prevTime) even in een variabele, alstjeblieft... :)
De vraag is eerder waarom zijn Vector3 class niet gewoon arithmetic operators implementeert zodat hij gewoon dit kan schrijven:
C++:
1
    result = (velocities - prevVelocities) * (1000000.0f / (time - prevTime));

;)

[ Voor 22% gewijzigd door .oisyn op 01-06-2016 11:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Alle reacties


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-10 11:07

Matis

Rubber Rocket

Ik heb de documentatie niet bij de hand, maar time since epoch klinkt mij als het aantal seconden sinds 1970.
Als je de functie tweemaal binnen dezelfde seconde aanroept, dan krijg je 0.

Al zal dit eenvoudig te debuggen zijn.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Het hangt van de onderliggende klok af maar dit is zeker mogelijk ja. Indien je timers met echt hoge resolutie wil zal je eerder naar de kernel jiffies/ticks moeten kijken :)

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

Verwijderd

En stop die *1000000.0f / (time - prevTime) even in een variabele, alstjeblieft... :)

Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

ikt schreef op dinsdag 31 mei 2016 @ 23:54:
Het gaat op zich goed, maar kan dit fout gaan?
Ja. std::chrono::system_clock is niet gegarandeerd monotinically increasing. Als iemand de tijd aanpast (zoals een NTP service) dan reflecteert dat terug in de huidige tijd. Je bent ook helemaal niet geïnteresseerd in de huidige tijd, maar gewoon in een delta. Daar is std::chrono::steady_clock voor.

Meer specifieker ingaand op je vraag, je zult altijd rekening moeten houden met het feit dat de tijd tussen 2 calls niet groot genoeg is om dat terug te zien in het antwoord. Al zal dat in een typische gameloop op 60+ fps redelijk zeldzaam zijn. Bij mij (VC++ 2015 op Win10) is std::chrono::steady_clock::period 1ns.
Verwijderd schreef op woensdag 01 juni 2016 @ 00:57:
En stop die *1000000.0f / (time - prevTime) even in een variabele, alstjeblieft... :)
De vraag is eerder waarom zijn Vector3 class niet gewoon arithmetic operators implementeert zodat hij gewoon dit kan schrijven:
C++:
1
    result = (velocities - prevVelocities) * (1000000.0f / (time - prevTime));

;)

[ Voor 22% gewijzigd door .oisyn op 01-06-2016 11:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-10 14:49
Verwijderd schreef op woensdag 01 juni 2016 @ 00:57:
En stop die *1000000.0f / (time - prevTime) even in een variabele, alstjeblieft... :)
Met welke reden wil je dat doen?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Sowieso is die code trouwens niet cross implementation complatible. std::chrono::system_clock::period is bij mij een ratio<1,10000000>, oftewel 100ns. Dit kan op elk systeem anders zijn.

Als je 'm naar secondes wilt converten dan zul je iets met die period moeten doen, of hem moeten casten naar een std::chrono::duration<float> (of double):
C++:
1
result = (velocities - prevVelocities) / std::chrono::duration<float>(time - prevTime).count();

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

farlane schreef op woensdag 01 juni 2016 @ 09:35:
Met welke reden wil je dat doen?
Het is een functie die heel vaak aangeroepen wordt - dan is het niet heel efficient om dezelfde berekening 3 keer uit te voeren.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
De gemiddelde compiler "optimaliseert" dat zels nog als optimalisaties uit staan :).

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
.oisyn schreef op woensdag 01 juni 2016 @ 10:07:
Sowieso is die code trouwens niet cross implementation complatible. std::chrono::system_clock::period is bij mij een ratio<1,10000000>, oftewel 100ns. Dit kan op elk systeem anders zijn.

Als je 'm naar secondes wilt converten dan zul je iets met die period moeten doen, of hem moeten casten naar een std::chrono::duration<float> (of double):
C++:
1
result = (velocities - prevVelocities) / std::chrono::duration<float>(time - prevTime).count();
Ik zo'm casten naar std::chrono::milliseconds. std::chrono::duration<float> lost het probleem van een onbekende tick-lengte niet op.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • +1 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waarom zou het casten naar milliseconds dat wél oplossen dan, afgezien van het feit dat ms-resolutie over het algemeen te laag is voor game-based physics simulations? Als je input te granular is kan hij er moeilijk extra bits bijverzinnen.
MSalters schreef op woensdag 01 juni 2016 @ 12:25:
De gemiddelde compiler "optimaliseert" dat zels nog als optimalisaties uit staan :).
Nou ja, er zal iig een losse mul en een div worden gedaan omdat fp berekeningen strict gezien niet associatief zijn ;)

[ Voor 40% gewijzigd door .oisyn op 01-06-2016 12:38 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
MSalters schreef op woensdag 01 juni 2016 @ 12:25:
De gemiddelde compiler "optimaliseert" dat zels nog als optimalisaties uit staan :).
Dat lijkt me niet, want numerieke vermenigvuldiging is niet commutatief.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Goed punt .oisyn, ik heb standaard de unsafe optimalisaties aanstaan en dan is is het wel associatief. (FP vermenigvuldiging is wel altijd commutatief, a*b = b*a).

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nou ja, ze zijn natuurlijk niet commutatief in de zin dat a*b*c != a*c*b. Al is het me niet helemaal duidelijk of commutativeit wel de goede term daarvoor is.

[ Voor 39% gewijzigd door .oisyn op 01-06-2016 14:42 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • ikt
  • Registratie: Juli 2008
  • Laatst online: 00:02
Het is een Vector3 die een struct is en door de SDK zo wordt aangeboden:
code:
1
2
3
4
5
6
7
8
9
10
11
#pragma pack(push, 1)
typedef struct
{
    float x;
    DWORD _paddingx;
    float y;
    DWORD _paddingy;
    float z;
    DWORD _paddingz;
} Vector3;
#pragma pack(pop)


Uit std::chrono::system_clock::now().time_since_epoch().count(); rolt het aantal microseconden: 14647592373918611 nu. - Wel zal ik meteen std::chrono::steady_clock gebruiken, dat ziet er al wat veiliger uit.

De bedoeling is overigens om iets te krijgen als
C++:
1
result.x = (1000000.0f * (velocities.x - prevVelocities.x)) / (time - prevTime);


Edit:
Uit de system_clock rolt het aantal in 100ns, uit steady_clock rolt 1ns accuracy uit.

[ Voor 7% gewijzigd door ikt op 01-06-2016 20:21 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hou er rekening mee dat dat per implementatie kan verschillen. Het handigst is ook het naar secondes te converteren zoals ik liet zien :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-10 14:49
.oisyn schreef op woensdag 01 juni 2016 @ 12:35:
Nou ja, er zal iig een losse mul en een div worden gedaan omdat fp berekeningen strict gezien niet associatief zijn ;)
Hmm inderdaad, niet aan gedacht.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • ikt
  • Registratie: Juli 2008
  • Laatst online: 00:02
.oisyn schreef op woensdag 01 juni 2016 @ 21:36:
Hou er rekening mee dat dat per implementatie kan verschillen. Het handigst is ook het naar secondes te converteren zoals ik liet zien :)
Dat is inderdaad handiger dan *1e9 :) Ik moet toch m/s^2 hebben en volgens mij rolt dit er redelijk goed uit nu.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 11-10 19:15
ikt schreef op dinsdag 31 mei 2016 @ 23:54:
Voor de deling:
code:
1
2
3
if (time == prevTime) {
    prevTime = time - 1;
}
Op deze manier voorkom je wel de deling door nul, maar de acceleratievector die je berekent zal niet kloppen. Mijns inziens is dit dus niet de goede oplossing. Als time == prevTime (met een monotone klok, zoals .oisyn al noemde) kun je beter de hele berekening overslaan, en prevVelocities en prevTime bewaren voor de volgende keer.
.oisyn schreef op woensdag 01 juni 2016 @ 01:18:
Bij mij (VC++ 2015 op Win10) is std::chrono::steady_clock::period 1ns.
Maar is dat alleen de resolutie, of ook de nauwkeurigheid van de klok? Het kan best zo zijn dat de tijd in nanoseconden wordt gerapporteerd, terwijl de werkelijke nauwkeurigheid lager is.
Pagina: 1