Reading these nerd essays are lowkey entertaining af, even tho I have fuck all idea what you two are on about lmfao.
SetsulI haven't checked whether it's 20% of 20.5% though. If it is 20.5% then you should be always getting 41 on some servers and might get 41 or 40 depending on whether the number you started with was odd or even on others.
If you want my theory on why it was "discovered" on villa it's that engie positions are usually next to medium or larger ammo packs.
float flPackRatio = PackRatios[GetPowerupSize()];
int iMaxMetal = pTFPlayer->GetMaxAmmo(TF_AMMO_METAL);
if ( pTFPlayer->GiveAmmo( ceil(iMaxMetal * flPackRatio), TF_AMMO_METAL, true, kAmmoSource_Pickup ) )
{
bSuccess = true;
}
class CAmmoPackSmall : public CAmmoPack
{
public:
DECLARE_CLASS( CAmmoPackSmall, CAmmoPack );
powerupsize_t GetPowerupSize( void ) { return POWERUP_SMALL; }
virtual const char *GetAmmoPackName( void ) { return "ammopack_small"; }
float PackRatios[POWERUP_SIZES] =
{
0.2, // SMALL
0.5, // MEDIUM
1.0, // FULL
};
I looked through the tf2 files and it looks like they define the packratios as float and don't change it from a float before performing multiplication, so I think it all comes down to arguments about what can result in floating point imprecision on handling .2 as a float rather than any other factor.
Those aren't necessarily in order and come from different files, but I figure it's clear enough as to confirming the idea of why I listed what I did.
I haven't checked whether it's 20% of 20.5% though. If it is 20.5% then you should be always getting 41 on some servers and might get 41 or 40 depending on whether the number you started with was odd or even on others.
If you want my theory on why it was "discovered" on villa it's that engie positions are usually next to medium or larger ammo packs.[/quote]
[code]float flPackRatio = PackRatios[GetPowerupSize()];
int iMaxMetal = pTFPlayer->GetMaxAmmo(TF_AMMO_METAL);
if ( pTFPlayer->GiveAmmo( ceil(iMaxMetal * flPackRatio), TF_AMMO_METAL, true, kAmmoSource_Pickup ) )
{
bSuccess = true;
}
class CAmmoPackSmall : public CAmmoPack
{
public:
DECLARE_CLASS( CAmmoPackSmall, CAmmoPack );
powerupsize_t GetPowerupSize( void ) { return POWERUP_SMALL; }
virtual const char *GetAmmoPackName( void ) { return "ammopack_small"; }
float PackRatios[POWERUP_SIZES] =
{
0.2, // SMALL
0.5, // MEDIUM
1.0, // FULL
};
[/code]
I looked through the tf2 files and it looks like they define the packratios as float and don't change it from a float before performing multiplication, so I think it all comes down to arguments about what can result in floating point imprecision on handling .2 as a float rather than any other factor.
Those aren't necessarily in order and come from different files, but I figure it's clear enough as to confirming the idea of why I listed what I did.
plunkbro go touch some grass its a fucking ammopack
You just can't appreciate a good mystery.
Also engie is clearly the most important class, since an engie main owns RGL.
JarateKingFor possible cause 1, if it's determined at compile-time then shouldn't it be consistent?
Yes, consistent on the same server. But that doesn't mean that windows servers, linux servers, windows clients, linux clients, and different versions of any of them would behave the same.
JarateKingFor possible cause 2, it's true that storing 0.2 into an 80-bit floating point can cause this behavior, but why is it inconsistent depending on the system? I would've assumed that which instructions to use would be determined at compile-time, is this not the case? As well, you mention support for SSE2, but shouldn't essentially every processor used today support SSE2 (considering it was introduced by Intel in 2000 and became compatible with AMD in 2003)?
Yes, it also happens with 0.2 as a float, then multiplying as a double. https://ideone.com/8OGbDL
Yes, virtually all CPUs support SSE2 nowadays, but it's not mandatory for TF2 as far as I know. r_sse2 exists so I assume both an x87 and SSE codepath exist in the binary. Should, for whatever reason, not all servers use the same path you can get different results.
The third is an external cause. I have to clarify, it's about which rounding mode is set during the MaxMetal * PackRatio multiplication before the ceil. Yes, the wrong rounding mode during ceil would turn it into a floor and result in 40 no matter what, but first we need the rounding after the multiply to round up to get 40.something or what FRNDINT does doesn't matter since 40.0 isn't affected either way.
Anyway, in a perfect world you set your rounding mode, your calculations run, and everything is done like you wanted it to be done. In the real world TF2 is not the only thing running on that CPU and execution might be interrupted at any point. When control is returned to this function the FPU should have been restored to the exact same state. But sometimes people write code that isn't quite correct and don't clean up after themselves. They changed the rounding mode and forgot to change it back, or they changed it to the default (but yours wasn't the default), or many other things they should never, ever do, but did for whatever reason. That basically means that if some 30 year old code with a single line missing is run at the wrong time your result changes and there's nothing you can do about it.
Granted, you have to be exceptionally unlucky for it to happen if you set the rounding mode and literally the next instruction is what depends on it (like in __ceill), but if you've been running with the same rounding mode for a while, never changing it, then it could absolutely happen and would persist until the next time the control word is changed. Most calculations wouldn't be noticeably affected, just the rare ones like this where a tiny error ends up being amplified.
It can't happen with SSE because those instructions always use round to nearest, ties to even. Though on the newer ones you can set it (like for ROUNDSD), but it's via an immediate so it's guaranteed to use whatever mode you set.
Given that Zesty is consistently getting 40 and I'm consistently getting 41 this can't be the main mechanism. Even if it happened (and you can see why that would be bad for so many reasons) it should be inconsistent and rare.
Also, I don't claim that it has to be any of those options, those are just what I could think of off the top of my head. I can only guarantee that it's not ceil working differently depending on the environment (the rules are pretty clear cut on what's larger than 40 and what isn't. that's not left to the implementation) or a multiplication by 1 gone horribly wrong (2 and 3/4 in mastercoms' list).
EDIT:
#32
mastercoms alt?
You just can't appreciate a good mystery.
Also engie is clearly the most important class, since an engie main owns RGL.
[quote=JarateKing]For possible cause 1, if it's determined at compile-time then shouldn't it be consistent?[/quote]
Yes, consistent on the same server. But that doesn't mean that windows servers, linux servers, windows clients, linux clients, and different versions of any of them would behave the same.
[quote=JarateKing]For possible cause 2, it's [url=https://www.ideone.com/Efnddz]true[/url] that storing 0.2 into an 80-bit floating point can cause this behavior, but why is it inconsistent depending on the system? I would've assumed that which instructions to use would be determined at compile-time, is this not the case? As well, you mention support for SSE2, but shouldn't essentially every processor used today support SSE2 (considering it was introduced by Intel in 2000 and became compatible with AMD in 2003)?
[/quote]Yes, it also happens with 0.2 as a float, then multiplying as a double. https://ideone.com/8OGbDL
Yes, virtually all CPUs support SSE2 nowadays, but it's not mandatory for TF2 as far as I know. r_sse2 exists so I assume both an x87 and SSE codepath exist in the binary. Should, for whatever reason, not all servers use the same path you can get different results.
The third is an external cause. I have to clarify, it's about which rounding mode is set during the MaxMetal * PackRatio multiplication before the ceil. Yes, the wrong rounding mode during ceil would turn it into a floor and result in 40 no matter what, but first we need the rounding after the multiply to round up to get 40.something or what FRNDINT does doesn't matter since 40.0 isn't affected either way.
Anyway, in a perfect world you set your rounding mode, your calculations run, and everything is done like you wanted it to be done. In the real world TF2 is not the only thing running on that CPU and execution might be interrupted at any point. When control is returned to this function the FPU [i]should[/i] have been restored to the exact same state. But sometimes people write code that isn't quite correct and don't clean up after themselves. They changed the rounding mode and forgot to change it back, or they changed it to the default (but yours wasn't the default), or many other things they should never, ever do, but did for whatever reason. That basically means that if some 30 year old code with a single line missing is run at the wrong time your result changes and there's nothing you can do about it.
Granted, you have to be exceptionally unlucky for it to happen if you set the rounding mode and literally the next instruction is what depends on it (like in __ceill), but if you've been running with the same rounding mode for a while, never changing it, then it could absolutely happen and would persist until the next time the control word is changed. Most calculations wouldn't be noticeably affected, just the rare ones like this where a tiny error ends up being amplified.
It can't happen with SSE because those instructions always use round to nearest, ties to even. Though on the newer ones you can set it (like for ROUNDSD), but it's via an immediate so it's guaranteed to use whatever mode you set.
Given that Zesty is consistently getting 40 and I'm consistently getting 41 this can't be the main mechanism. Even if it happened (and you can see why that would be bad for so many reasons) it should be inconsistent and rare.
Also, I don't claim that it has to be any of those options, those are just what I could think of off the top of my head. I can only guarantee that it's not ceil working differently depending on the environment (the rules are pretty clear cut on what's larger than 40 and what isn't. that's not left to the implementation) or a multiplication by 1 gone horribly wrong (2 and 3/4 in mastercoms' list).
EDIT:
#32
mastercoms alt?
Setsul
EDIT:
#32
mastercoms alt?
nah I just wanted to see if my pea brain was enough to be usefully clear about the tf2 end of things because nobody just grabbed the bits from the TF2 source where we actually confirm the issue is multiplying 200 by .2(float) as still float. I don't have a part in the actual "why is the floating point not precise" part because the only C I've ever touched is editing keybinds and font in dmenu.
Mastercoms pulled what the end result of putting all that together would be, but not the part where it's defined as a float and not changed from a float.
EDIT:
#32
mastercoms alt?[/quote]
nah I just wanted to see if my pea brain was enough to be usefully clear about the tf2 end of things because nobody just grabbed the bits from the TF2 source where we actually confirm the issue is multiplying 200 by .2(float) as still float. I don't have a part in the actual "why is the floating point not precise" part because the only C I've ever touched is editing keybinds and font in dmenu.
Mastercoms pulled what the end result of putting all that together would be, but not the part where it's defined as a float and not changed from a float.
Ah, misinterpreted the "why I listed what I did", my mind immediately went to that actual list.
Thanks for confirming those things!
Thanks for confirming those things!
someone better get to the bottom of this and do some A/B testing on various different types of servers and find which combinations lead to 41 metal and then alert the engi mains, that one extra metal means running mini sentry engi full time is viable
Has anyone checked to make absolutely sure that the one extra metal isn't a visual glitch yet? There's only one reasonable way of doing that, of course, and it's to build and destroy minisentries for long enough that the extra metal from the small pack allows you to build an additional building that you would otherwise not have had enough metal to build. Also, do it on host_timescale 0.1 so we can be sure there are no splices in the video - oh, did I mention that there needs to be a video? This is important evidence for the case being built here, and without it, your nerd essays will all amount to naught but ashes in the face of such substantial missing experimental evidence. Obviously.
weedyabysscosmic radiation bit flip
thread ended on #4 yall didnt have to type dissertations on it :/
thread ended on #4 yall didnt have to type dissertations on it :/
[img]https://imgur.com/a/NdxENsZ[/img]
No, servers have ECC.
#5 is correct, we've been over this.
zx37rounded up
#5 is correct, we've been over this.
[quote=zx37]rounded up[/quote]
SetsulI think now everyone can understand why I ... dislike x87.
This line kills me. As if everyone here speaks fluent assembly.
On the real, as a software guy, this thread is really cool. 10/10
This line kills me. As if everyone here speaks fluent assembly.
On the real, as a software guy, this thread is really cool. 10/10
I think even those who have never seen assembly can tell that to round a number a single instruction with "round" in its name is preferable to a giant wall of asm that needs a comment to even identify the instruction that does the rounding.
But I'm glad it's at least amusing to those who don't have to suffer through it.
But I'm glad it's at least amusing to those who don't have to suffer through it.
Not sure how much of this was said in this thread already but this is a more accessible explanation
Not sure how much of this was said in this thread already but this is a more accessible explanation
i was going to fix this myself, but my friend nosoop already did it lol
https://gist.github.com/nosoop/e4d83bdb6ac9409a638aaef2ae38f48f
:D
https://gist.github.com/nosoop/e4d83bdb6ac9409a638aaef2ae38f48f
:D
SetsulFor float that means the choice is between 0.199999988079071044921875 and 0.20000000298023223876953125. The latter is simply closer to the "true value" 0.2 than the former.
So who determines how rounding is done between IEEE and the CPU architecture maker?
So who determines how rounding is done between IEEE and the CPU architecture maker?
stephi was going to fix this myself, but my friend nosoop already did it lol
https://gist.github.com/nosoop/e4d83bdb6ac9409a638aaef2ae38f48f
:D
Please do not utilize this change, my windows server needs to stay quirked up.
https://gist.github.com/nosoop/e4d83bdb6ac9409a638aaef2ae38f48f
:D[/quote]
Please do not utilize this change, my windows server needs to stay quirked up.