Complex numbers não são complicados.
Só precisam de um nome menos assustador.
Eles são tão úteis, especialmente em engenharia e ciência, que o R inclui números complexos como tipos atômicos padrão, ao lado de integer, double, logical, character e raw.
Um número complex em R é um único valor.
Na prática, porém, dá para pensar nele como um par de números.
Essas partes são chamadas de "real" e "imaginária", por razões históricas infelizes.
Mais uma vez, o melhor é focar na simplicidade por trás de tudo, e não nos nomes estranhos.
Para criar números complexos a partir de dois números reais, basta adicionar o sufixo i à parte imaginária.
2+3i
#> [1] 2+3i
typeof(2+3i)
#> [1] "complex"
Para criar um número complexo a partir de variáveis reais, a sintaxe acima não funciona.
Escrever r + imi confunde o parser, fazendo-o pensar que imi é um nome de variável (inexistente).
Multiplique a parte imaginária por 1i ou use a função [complex()][ref-complex]:
r <- 2
im <- 3
r + im * 1i
#> [1] 2+3i
# must include the `real` and `imaginary` keywords
complex(real = r, imaginary = im)
#> [1] 2+3i
Você pode se perguntar: por que i e não j?
A maioria dos engenheiros prefere j.
A maioria dos cientistas e matemáticos prefere a notação matemática i para imaginário, mas essa notação entra em conflito com o uso de i para significar corrente na Engenharia Elétrica.
O R escolheu i, o Python escolheu j, e o Julia contornou a polêmica escolhendo im.
Tenha cuidado ao alternar entre linguagens de programação [STEM][wiki-STEM].
Para acessar as partes de um número complexo individualmente:
z <- 2+3i
Re(z) # real part
#> [1] 2
Im(z) # imaginary part
#> [1] 3
Qualquer uma das partes pode ser zero, e os matemáticos podem então dizer que o número é "totalmente real" ou "totalmente imaginário". No entanto, ele ainda é um número complexo em R.
1.2 + 0i
#> [1] 1.2+0i
typeof(1.2 + 0i)
#> [1] "complex"
2i
#> [1] 0+2i
typeof(2i)
#> [1] "complex"
Você talvez já tenha ouvido que "i (ou j) é a raiz quadrada de -1".
Por enquanto, tudo o que isso significa é que a parte imaginária, por definição, satisfaz a seguinte igualdade:
1i * 1i == -1 # more precisely, 1i * 1i == -1 + 0i
#> [1] TRUE
É uma ideia simples, mas leva a consequências interessantes.
A maioria dos operadores usados com números de ponto flutuante e inteiros também funciona com números complexos:
z1 = 1.5 + 2i
z2 = 2 + 1.5i
z1 + z2 # addition
#> [1] 3.5+3.5i
z1 * z2 # multiplication
#> [1] 0+6.25i
z1 / z2 # division
#> [1] 0.96+0.28i
z1^2 # exponentiation
#> [1] -1.75+6i
2^z1 # another exponentiation
#> [1] 0.518895+2.780422i
A maioria das funções matemáticas funciona com entradas complexas.
Existem várias funções, além de Re() e Im(), com relevância especial para números complexos.
Conj() simplesmente inverte o sinal da parte imaginária de um número complexo (de + para -, ou vice-versa).
abs(<complex number>) tem garantia de retornar um número real sem parte imaginária (sua "magnitude"), e Mod(<complex number>) é um sinônimo.Arg(<complex number>) retorna o ângulo de fase em radianos.z1
#> [1] 1.5+2i
abs(z1)
#> [1] 2.5
Mod(z1) # same as previous
#> [1] 2.5
Conj(z1) # flip sign
#> [1] 1.5-2i
Arg(z1)
#> [1] 0.9272952
Você acaba de ser contratado por um novo serviço de táxi que está tentando se diferenciar de outras ofertas em um mercado já saturado. Para conseguir isso, o CEO decidiu oferecer um serviço ultraluxuoso em Manhattan, com atendentes em cada interseção para ajudar os clientes antes e depois da corrida. Agora, você precisa escrever um código que ajude nas operações do serviço.
Seu CEO decidiu que, como Manhattan tem um traçado de ruas majoritariamente em grade, os números complexos são uma forma conveniente de representar as interseções das ruas. Nesse sistema, números reais positivos e negativos representam leste e oeste, e números imaginários positivos e negativos representam norte e sul, respectivamente.
Como instanciar um número complexo em R é um pouco, hã... peculiar, você recebeu instruções para implementar uma função simples de número complexo.
Implemente a função simplex(a, b), que recebe os números inteiros a e b.
Retorne o número complexo a+bi.
simplex(1, 1)
#> 1+1i
simplex(-3, 4)
#> -3+4i
Quando um cliente informa a interseção de destino, seus motoristas recebem as direções de como chegar lá. Essas direções vêm na forma de um número complexo, em que a parte real representa quantos quarteirões andar para norte/sul e a parte imaginária representa a distância leste/oeste. Para se alinhar a uma bússola canônica, seu gerente de projeto decidiu que o norte estará na direção imaginária positiva e o sul, na direção imaginária negativa. Da mesma forma, o leste está na direção real positiva e o oeste, na direção real negativa.
Implemente a função driver_directions(start, end), que recebe as coordenadas da interseção de partida (start) e as coordenadas do destino (end).
Retorne um número complexo que representa quantos quarteirões leste/oeste + norte/sul o motorista precisa percorrer.
driver_directions(0+0i, 7+5i)
#> 7+5i
driver_directions(-2+3i, 4-5i)
#> 6-8i
O cliente paga uma taxa pela distância que o táxi precisa percorrer. Como Manhattan tem um traçado de ruas em grade, os táxis só podem circular por essas vias. Essa estrutura leva a uma medida de distância que é obrigada a seguir as linhas da grade. A distância pode ser obtida somando o número de linhas percorridas ou o número de interseções alcançadas (ou seja, sem contar a interseção de partida). Essa medida é comumente chamada de distância de Manhattan ou norma L1.
Implemente a função manhattan(start, end), que recebe as interseções start e end.
Retorne a distância de Manhattan entre as interseções start e end.
manhattan(0+0i, 3+4i)
#> 7
manhattan(-2-3i, -1+1i)
#> 5
O CEO conseguiu atrair bancos de investimento ao destacar que o serviço não é apenas ultraluxuoso, mas também verde, porque vai usar corvos treinados para transportar mensagens entre os atendentes nas interseções (que repassam informações sobre os passageiros para uma experiência personalizada). Parece que nenhum dos banqueiros de investimento se deu ao trabalho de investigar por que exatamente isso é ecologicamente correto, ou mesmo que tipo de CEO gosta de treinar corvos nas horas vagas, porque o dinheiro dos investimentos não parou de entrar.
Esse serviço também é cobrado pela distância percorrida. No entanto, como os corvos podem voar, eles não precisam seguir a malha viária em grade e podem pegar o caminho mais curto. É claro que talvez não seja esse o caso quando há arranha-céus enormes, mas o CEO está implantando esse serviço em Manhattan, no Kansas (também conhecida como "The Little Apple"), onde os corvos podem facilmente sobrevoar os prédios baixos. A demanda potencial por um serviço assim em Manhattan, no Kansas, e como os pedestres locais vão se sentir com todos esses pássaros voando por cima são assuntos para outro dia.
Implemente a função as_crow_flies(start, end), que recebe as interseções start e end.
Retorne a distância em linha reta entre as duas.
as_crow_flies(0+0i, 3+4i)
#> 5
Seu CEO treinou os corvos para seguir tipos de direções semelhantes às dos motoristas. No entanto, o CEO adora o Hemisfério Sul e treinou os corvos usando uma bússola diferente da que seu gerente de projeto usa para o resto do sistema. Seu CEO está se revelando uma pessoa bastante excêntrica. A bússola do CEO tem o norte na direção imaginária negativa e o sul na direção imaginária positiva. Isso é o oposto das direções norte/sul dos motoristas, enquanto leste/oeste permanecem iguais.
Implemente a função crows_directions(start, end), que recebe as interseções start e end.
Retorne o número complexo análogo às direções do motorista, mas com norte/sul invertidos.
driver_directions(0+0i, 7+5i)
#> 7-5i
driver_directions(-2+3i, 4-5i)
#> 6+8i
Crie sua conta no Exercism para aprender e dominar R com 21 conceitos111 exercícios e mentoria humana de verdade, tudo de graça.