Jump to content
Guest id194

Compactar pedaço de código sem usar ifs

Recommended Posts

Guest id194

Tenho a seguinte funçãozita:

float anglePitch = 0.0f;

void Camera::Pitch(float angle) {
anglePitch += angle;

if(anglePitch <= -90.0f) {
	anglePitch = -90.0f;
	return;
}

if(anglePitch >= 90.0f) {
	anglePitch = 90.0f;
	return;
}

(...)
}

Não consigo parar de pensar (não sei porquê) que deve haver alguma maneira manhosa (mas simples) de simplificar aqueles ifs mas ao mesmo tempo limitar o valor de anglePitch a ficar entre -90 e 90. O ideal seria livrar-me dos dois, algum tipo de operação a nível de bits que me conseguisse fazer aquilo ou alguma operação matemática. Alguém tem ideias ou não será possível? Se não, uma alternativa seria só com um único if, mas não estou a ver como.

Será que estou a querer inventar de mais ou alguém consegue compactar isto?  🤔

Share this post


Link to post
Share on other sites
mjamado

Localhost, isso nem sequer faz a mesma coisa...  :) Se o ângulo for, por exemplo, -50, fica 90...  👎

Nazgulled, e que tal:

if(abs(anglePitch) > 90)
{
  anglePitch = 90 * (abs(anglePitch) / anglePitch);
  return;
}

Ou, usando um operador ternário tal como disse o Localhost - só que depois perdes a capacidade de fazer o return nos casos que mostras:

anglePitch = (abs(anglePitch) > 90) ? 90 * (abs(anglePitch) / anglePitch) : anglePitch;

Repara que precisas da biblioteca cmath para teres o abs de números float.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites
Triton

Retirado do meu engine:

// Clamps a variable to the given range.
template< typename T > bool MathClamp( T& var, T min = 0, T max = 1 )
{
// Equivalent to: max(min, min(var, max))
if( var >= max )
{
	var = max;
	return true;
}
else if( var <= min )
{
	var = min;
	return true;
}

return false;
}

Exemplo de uso:

static const float DEFAULT_LIMIT_XAXIS = 89.0f;

// Restrict X-axis movement.
float& xang = rotation.x;
MathClamp( xang, -DEFAULT_LIMIT_XAXIS, DEFAULT_LIMIT_XAXIS );

Não uso os 90 porque dava um problema algures nas contas.

E como tenho em comentário no código, um clamp é equivalente ao: max(min, min(var, max))


<3 life

Share this post


Link to post
Share on other sites
Guest id194

O operador ternário já tinha pensando mas tem o problema que já mencionaram e o código ficada demasiado confuso.

A outra opção talvez fique mais simpática e eu tentei fazer algo semelhante, mas não estava a conseguir, estava-me a escapar o abs() na divisão e o ângulo ficava sempre positivo :wallbash:

Thanks.

Quem tiver ideias ainda mais compactas ou engraçadas, pode mandar  :)

@Triton

Isso é overkill para o que eu quero lol, não estou a fazer nenhum motor como tu :P

Share this post


Link to post
Share on other sites
Triton

@Triton

Isso é overkill para o que eu quero lol, não estou a fazer nenhum motor como tu :)

É overkill onde? Resolve exactamente o mesmo problema duma maneira simples e compacta.

Este pessoal com medo dos templates...

Mas assim não te chega?

float anglePitch = std::max(-90.0f, std::min(anglePitch, 90.0f));


<3 life

Share this post


Link to post
Share on other sites
Guest id194

Lá estás tu com o teu mau feitio de supor tudo... Nem se quer sei o que são templates, por isso não posso ter medo do que quer que seja. É overkill porque é completamente desnecessário (no meu caso) escrever uma função para fazer uma simples operação.

Mas como é que achas isso compacto? Eu vim aqui pedir que meia dúzia de linhas fossem tornadas em menos linhas e tu das-me uma solução que envolve a escrita de uma função extra para o efeito. Onde é que isso é mais compacto que o que eu já tinha?

É um código mais portável e reutilizável? Acredito que sim, mas não foi isso que eu pedi (nem o que preciso) :)

A solução que deste mais abaixo já faz mais sentido e essa sim já é compacta, mas continuo a preferir a anterior.

Share this post


Link to post
Share on other sites
Triton

Mas como é que achas isso compacto? Eu vim aqui pedir que meia dúzia de linhas fossem tornadas em menos linhas e tu das-me uma solução que envolve a escrita de uma função extra para o efeito. Onde é que isso é mais compacto que o que eu já tinha?

É um código mais portável e reutilizável? Acredito que sim, mas não foi isso que eu pedi (nem o que preciso) :)

O código abstrai o cálculo numa operação conhecida (Clamp) e torna o código muito mais fácil de ler. Tudo bem que o código não é mais pequeno que o que tu tens (se considerades o template também), mas o template tem a vantagem muitas vezes de não ter overhead da chamada de função, porque é quase sempre inlined no código que chama.

Não te esqueças também que no fim o que interessa não é só o código de alto nível, mas o código gerado assembly.

As soluções apresentadas anteriormente são na minha opinião todas inferiores. A do mjamado é mais complicada de perceber. Ao inicio até me pareceu que tinha problemas com divisão por zero, mas não. Tem uma divisão que é algo super lento comparado com o resto e ainda chama funções (absolute).

Mas o objectivo do código que dei era veres a equivalência que mostrei no post anterior. Com isso tens algo simples, e fica tudo numa linha.

By the way, encontrei uma discussão sobre isto: http://stackoverflow.com/questions/427477/fastest-way-to-clamp-a-real-fixed-floating-point-value


<3 life

Share this post


Link to post
Share on other sites
Guest id194

Vou voltar a repetir, eu não estou a fazer um motor como tu.

O código assembly e essas tretas todas são completamente irrelevantes para aquilo que eu quero, mas principalmente, para aquilo que eu preciso neste momento. Eu gostava de entender porque que às vezes complicam sempre tanto. Eu coloquei uma questão tão simples...

Essas coisas são todas muito bonitas e interessantes (não estou a ser sarcástico) mas neste caso eu coloquei uma questão simples à procura de uma resposta ainda mais simples. E tu vieste complicar com coisas que neste momento não me interessa aprender nem se quer tenho tempo/necessidade para tal.

A única coisa que eu não gostei na versão de uma linha é o facto de não puder fazer o return caso o ângulo ultrapasse o limite.

Share this post


Link to post
Share on other sites
mjamado

Mas assim não te chega?

float anglePitch = std::max(-90.0f, std::min(anglePitch, 90.0f));

Olha... 🤔 Passou pelos pingos da chuva, essa solução...  :)


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites
Triton

Olha... 🤔 Passou pelos pingos da chuva, essa solução...  :)

:confused:

Vou voltar a repetir, eu não estou a fazer um motor como tu.

Tudo bem, mas isso não tem relevância.

O código assembly e essas tretas todas são completamente irrelevantes para aquilo que eu quero, mas principalmente, para aquilo que eu preciso neste momento. Eu gostava de entender porque que às vezes complicam sempre tanto. Eu coloquei uma questão tão simples...

Não é preciso perceber de assembly para saber que divisões sao bastante lentas. Pensei que também te interesasse a tradeoffs de performance. É algo que ao início não se pensa, mas quando começas a ter problemas de performance, todas as migalhas contam. :P

Essas coisas são todas muito bonitas e interessantes (não estou a ser sarcástico) mas neste caso eu coloquei uma questão simples à procura de uma resposta ainda mais simples. E tu vieste complicar com coisas que neste momento não me interessa aprender nem se quer tenho tempo/necessidade para tal.

Fair enough. Mas eu não sei o que tu achas complicado ou não. Para mim aquilo é super simples.

A única coisa que eu não gostei na versão de uma linha é o facto de não puder fazer o return caso o ângulo ultrapasse o limite.

Sim, e talvez também seja a razão porque não usei essa forma. Este código já tem uns meses / anos.


<3 life

Share this post


Link to post
Share on other sites
jpaulino

Ups, my bad! Estive mesmo mal agora lol.

Peço desculpa pelo off-topic, mas Localhost  não voltas a apagar respostas depois de serem comentadas, ok ?

Isso não se faz e todos se enganam/ou compreendem mal! :/

Share this post


Link to post
Share on other sites
Guest id194

Não é preciso perceber de assembly para saber que divisões sao bastante lentas. Pensei que também te interesasse a tradeoffs de performance. É algo que ao início não se pensa, mas quando começas a ter problemas de performance, todas as migalhas contam. :)

Lá está, contam no teu caso! Para o que eu estou a fazer, o impacto na performance vai ser pouco relevante. Se eu quisesse estar aqui a optimizar ao mais pequeno pormenor, nunca mais acabava o que tenho para fazer. Não digo que isso seja importante. É importante, mas depende da situação. E na minha situação, isso não importa para nada.

Fair enough. Mas eu não sei o que tu achas complicado ou não. Para mim aquilo é super simples.

Li assim por alto o que são templates e o código que deste de complicado tem pouco, mas eu não me estava a referir ao código ser complicado ou não. Vieste falar de uma coisa que não interessa e que não é relevante para a questão que eu coloquei, "complicaste".

@jpaulino

Se não querem que os utilizadores apaguem respostas, porquê que não desactivam a opção e pronto? 🤔

Share this post


Link to post
Share on other sites
mjamado
@jpaulino

Se não querem que os utilizadores apaguem respostas, porquê que não desactivam a opção e pronto? 🤔

Depois de serem comentadas. Repara que eu respondi uma coisa que, agora, não faz sentido - falta a resposta do Localhost antes... O pessoal que vier depois há-de ficar a pensar que eu não bato bem da bola...  :)


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites
jpaulino

Depois de serem comentadas. Repara que eu respondi uma coisa que, agora, não faz sentido - falta a resposta do Localhost antes... O pessoal que vier depois há-de ficar a pensar que eu não bato bem da bola...  :)

Essa é mesma a questão. Apagar todos podem apagar, agora depois de comentado não faz qualquer sentido ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.