Blog

[blog] «Governo encaminha extinção da CEITEC em seu melhor momento»

Do site A Revolução Industrial Brasileira:

Comento:

Um dos vários sintomas agudos do obscurantismo que tomou e continua a tomar conta do Brasil é a extinção da CEITEC. Nenhum espanto quanto a isso.

O espanto é a movimentação contra a sua extinção, praticamente anunciada desde antes da posse do atual governo, ter começado tão tardiamente pela comunidade de Alta Tecnologia brasileira. A CEITEC foi das primeiras empresas a serem ventiladas para desestatização. No caso a extinção sempre foi o caminho mais provável pela conjuntura.

Antes de qualquer informação oficial, o ex-Secretário de Desestatizações fartou-se em dar à imprensa relatos – no mínimo – desinformados sobre o que ocorria lá dentro (sem nenhuma réplica oficial da Companhia, friso), como o abaixo:

«Mattar também falou indiretamente do Ceitec: “Existem casos como o de uma estatal que deveria produzir um chip para monitorar os rebanhos. O tal chip, que é instalado na orelha do boi, nem é produzido no Brasil”. »

Não seria necessário comentar que a redução da CEITEC ao chamado “chip do boi” é proposital, ainda que não exista nenhum demérito neste produto. Soa demasiado simples para justificar a existência de uma Estatal. Basta um google para saber o que mais a CEITEC criou e cria. Isto se ainda quisermos manter o debate tacanho e falarmos só em produtos e não em estratégias de desenvolvimento nacional. Pensar que a CEITEC têm problemas a serem resolvidos ou que seu percurso desviou do desejável, é razoável. Entretanto a extinção como solução é só obscuro.

(Não é matéria da capa do jornal na data)

[blog] O Amplificador Diferencial

Comentários básicos sobre este workhorse em eletrônica. O conceito de amplificador diferencial é elemento-chave em uma infinidade de aplicações analógicas: buffers, filtros, osciladores, reguladores de tensão, referências de tensão/corrente, processamento de sinais, PLLs, etc., devido às suas propriedades úteis. As figuras foram retiradas do livro CMOS Circuit, Design, Layout and Simulation (Baker).

Figura retirada de analog.com

O Par diferencial

O conceito de diferencial é comum em engenharia e consiste na ideia de que determinado fluxo de energia é distribuído entre dois ramos ‘complementares’ de um dispositivo (no automóvel, isto permite que uma roda gire mais rápido que a oposta para que possamos fazer uma curva – cada uma das rodas vai percorrer diferentes comprimentos de arco no mesmo tempo). Em eletrônica o par diferencial nos permite principalmente eliminar ruídos de modo-comum (aqueles ruídos que são comum a dois condutores de um mesmo circuito).

O Amplificador Diferencial

A apresentação clássica do amplificador diferencial é assim:

Vout = (V+ – V)*Ganho [V]

Também sempre é dito que idealmente temos:

  • impedância de entrada infinita
  • impedância de saída nula
  • ganho infinito em malha aberta
  • rejeição de modo comum infinita

Vou tentar mostrar aqui porque estas características são importantes, utilizando circuitos analógicos CMOS básicos e análises intuitivas.

Talvez a primeira coisa que vem à mente de quem é introduzido ao assunto é que se o ganho é muito grande (como deve ser), a tensão Vout vai explodir. Primeiramente, esta equação está em malha aberta, sem a realimentação negativa, quando parte do sinal de saída é subtraído do sinal de entrada. Depois, na maior parte das vezes estamos interessados em trabalhar em pequenos sinais AC – centésimos ou milésimos de Vdd (v+, v-). Cabe ainda dizer que ganho mede-se em V/V (é um número sem dimensão), e independente do seu tamanho a máxima tensão alcançada será sempre Vdd.

Os pequenos sinais (v+,- v-) variam em torno da polarização DC (V+, V-). Polarizar significa determinar um ponto de operação do circuito, de cada transistor na verdade (em elementos semicondutores, as características elétricas variam conforme às tensões elétricas a que o dispositivo é submetido).  Na figura acima o ganho de malha aberta (open-loop) é mostrado como função da frequência do sinal de entrada. Uma topologia clássica do circuito amplificador diferencial em CMOS é assim:

(PS: transistores NMOS estarão em região linear se VGS >= Vth, e PMOS com VSG >= Vth e IDS = f(VDS,VGS), onde f assume formas distintas a depender da região de operação)

A corrente Iss é resultado da tensão de gate em M6, que estará com a corrente estável em um range de tensão dreno-fonte. Supondo uma tensão Vn, de modo comum aplicada aos gates de M1 e M2, a corrente drenada por M6 seja um valor Iss = Id1 + Id2.

Se extrairmos a tensão de saída no dreno de cada um dos transistores M1 e M2, Vout1,2= Id1,2*RCarga1,2. Isto basicamente diz que o ganho Av=Vout/Vin é proporcional à transcondutância do transistor em determinado ponto de polarização multiplicado pela carga, pois ID/Vin = Gm = 1/(Rds).

A saída Vout diferencial é VD1-VD2 ou ao contrário, a depender do que estabelecermos como saída positiva e negativa. Com a topologia acima é impossível dizer qualquer coisa sobre qual será a entrada positiva e qual será a negativa. Só podemos dizer isto quando definirmos qual a entrada que aumenta a tensão de saída, e a entrada que a diminui.

Para tanto, completa-se o par diferencial com uma carga espelho de corrente do tipo PMOS, uma carga ativa.

Se a tensão do gate M1 aumenta, mais corrente é drenada, maior a tensão VSG de M3 e M4 (ou menor a tensão VGS, se preferir). Se ambos M1 e M2 tiverem a mesma tensão de gate, a corrente no sentido dreno-fonte de cada elemento do par será ID1 = ID2 = Iss/2 [A]. Se tensão de gate em M1 aumenta em relação à tensão de gate M2, menos corrente é drenada por M2 e portanto menor a queda dreno-fonte em M2. Se M2 continuar no ponto de operação desejável, sua (trans)condutância é constante. Se a condutância de M2 mantém-se constante, mas sua corrente diminui, a tensão Vout = VDD – VSD4 obrigatoriamente aumenta. Então VG1 = V+. O raciocínio inverso vale para V: quanto maior a corrente drenada em M2, menor a tensão Vout. É este balanço na entrada que nos permite reduzir drasticamente o ruído de modo comum, se comparado a um amplificador de entrada única. Se adicionarmos mais um estágio de amplificação teremos ganho suficiente para chamá-lo de amplificador operacional. Tradicionalmente, o próximo estágio seria um amplificador PMOS, dreno-comum, com carga NMOS.

Ainda nesta topologia de só um estágio, a curva de transferência assume o seguinte, sendo o eixo horizontal a tensão de modo comum Vin nos gates do par diferencial, e no eixo vertical, Vout a tensão medida nos drenos de M2 e M4.

A derivada no ponto de polarização é o ganho do amplificador quando polarizado com a tensão correspondente Vin. Um bom ponto de polarização é aquela cuja derivada em relação ao pequeno sinal vin mantenha o maior intervalo em vout sem perturbar a transcondutância de M2 // M4. Idealmente é um ponto com derivada infinita. Pois para o sinal vout não remover M2 e M4 do ponto de operação desejável, as correntes drenadas não podem causar quedas de tensão que retire os transistores do ponto de operação, o que no limite significa impedância nula no nodo vout. Para a impedância de entrada ser infinita, a variação da tensão vgs de M1 e M2, não deve causar variação de tensão vgs + Vgs que retire o transistor da região de operação desejada. Se for saturado na região linear, a tensão dreno-fonte precisa manter-se em Vds >= tensão de overdrive (Vgs – Vth). A rejeição de modo comum será tão boa quanto a precisão do espelhamento de corrente – o mais iguais o módulo das correntes de dreno de M3 e M4, mais ruídos do sinal de tensão de modo-comum Vin estarão subtraídos no nodo Vout = Iout*RLout.

[blog] Synchronous versus asynchronous reset

Reset is about getting a system back to a known initial state. Temporary data is flushed. When I say data I mean 0s and 1s. Everything will be put to a known state so the circuit starts up. Sounds important.

When we go for synchronous or asynchronous reset, active low, our HDL code will look like one of these:

module synch_reset_pipeline(in1, in2, ..., out1, out2,...);
// #1 module with synchronous reset
always @(posedge clk) 
begin
  if (!rst) begin
   // reset logic: put this module to known state 
  end
  else begin
  // functional logic: processes data
  end
end
endmodule
module asynch_reset_pipeline(in1, in2, ..., out1, out2,...);
// #2 module with asynchronous reset
always @(posedge clk or negedge rst) 
begin
  if (!rst) begin
   // reset logic 
  end
  else begin
  // functional logic
  end
end
endmodule

To simplify, firstly, think about a single sequential element (a flip-flop). Then, imagine it is starting up, catching the very first data signal arriving on the input and propagating it to other pipeline stages. How would be a desirable reset signal? I would say:

  • it resets the circuit to a known state
  • not prone to any metastability
  • the duty cycle is just long enough to meet the above criteria

Given the above bullets what is the go for approach? Whatever fits the system better, on area, timing and power. On module #1, we are telling the tool that the reset signal is under the domain of the clock, and the reset logic will take place when reset level is low. So when the clock positive edge triggers and reset is asserted, the flops that are connected to that logic will reset. Therefore, the reset signal is pretty much another data signal (like: assign current_input = (!rst_sel) ? reset_value : next_input), selecting between the next value to be sampled or the reset data value, when a reset happens. And we should make sure it will be filtered from glitches and never prone to any meta-stability – but this is valid to any other external input too. It cannot take the fastest way through the datapath when asserted, otherwise it might reset the logic violating setup requirements, and therefore put it to a unknown state, that will be sampled and propagated. The deassertion by its turn need to respect the hold time of the signals that were propagated through the pipeline. As data and reset are on the same clock domain, the work relies pretty much on the clock tree synthesis. It costs more circuitry in general. (Although flops are smaller, they say)

On #2, the asynchronous reset is a high priority interruption, per say. The or inside the sensitivity list changes everything. Whenever reset is low (asserted) it comes to bring everything down and up again. If the pulse has a very low duty cycle, maybe the flop will not be stable yet, and will put the the circuit to an unknown state when reset is released; maybe a very bad combination (boom). That is, we need to model this asynchronous path to respect a time after asserting and before deasserting the signal, so we make sure every pipeline stage is at a known state. To prevent timing violation when asserting, we need to make sure the reset will take place respecting the (worst) removal time, so the initial data to be sampled is valid. For deasserting, we need to make sure the clock samples a stable value, by respecting the (worst) recovery time. Besides, you need to tell the tool that the signal that multiplex the input to your flops between operation data and reset data is a false path – that is the clock must ignore the impact of this signal on the data path, and not make any efforts to support setup and hold timings of the sequential elements. You will take care by yourself by controlling the reset behavior. A technique could be to model the buffers safely enough to charge and discharge on a determined relative time, so the reset removal and recovery time are always safe. That is you fix a positive delay for reset assertion and a negative delay for deassertion, regarding the active clock edge. You will need to synchronize the input reset signal to a common in both aproaches to mitigate metastability. Asynchronous reset costs less circuitry, but is also more complex: a very critical asynchronous control signal is on the game.

[blog] Tip: C variables and pointers declarations and definitions

It might sound naive, but it is a very common interview question, and I actually think the notation can be deceiving. And furthermore, it is essential. A few months off and you will be asking yourself “how is that again?”. Unless you get this rule: start reading from right to left.

Question: Please read the following declarations and explain their properties regarding read and write.

#1 int v;

Reads as v is a variable of integer type

int v; //declaration
int same_scope_var = 0x10; //declaration and definition
v = 0; //definition
v = same_scope_var; //redefinition v=0x10

After the scope (declaration) and initial value of v is defined, you can read and write it in run-time.

#2 int const v;

Reads as v is a constant integer, i.e., read-only

After the scope and initial value of v is defined, you can only read it in run-time.

#3 int *v;

Reads as v is variable pointer to an integer.

int *v; //declaration
int same_scope_var = 0xFFFFFFFF; //declaration and defitinion
int same_scope_var2 = 0xF0FFFFFF; //declaration and defitinion
v = &same_scope_var ; //definition
v = &same_scope_var2 ; //definition

After the scope and initial value (that is a memory address that holds an integer) of v is defined, you can change it to whatever other integer address you want in run-time.

#4 int const *v;

Reads as v is variable pointer to a constant integer; that is, the address v holds can change, although it is expected to point to a constant value.

int const same_scope_k = 0xFFFFFFFF; //declaration and defitinion
int const same_scope_k2 = 0xF0FFFFFF;
int same_scope_var = 0xF0FBFFFF;
int const *v; //declaration
v = &same_scope_k; //definition
v = &same_scope_k2; //redefinition
*v = same_scope_k; //error wont compile
v = &same_scope_var; //probably compile with a warning

After the scope and initial value of v is defined, you can write and read it whenever you want in run-time, but you cannot change the value it points to by dereferencing.

#5 int * const v;

Reads as v is a constant pointer to a variable integer, i.e., v is ready-only, but the value that it points to (dereference) can change.

int same_scope_variable  = 0xFFFFFFFF; //declaration and definition
int same_scope_variable2  = 0xF0FFFFFF; 
int * const v; //declaration
v = &same_scope_variable  ; //definition
*v = same_scope_variable2; // redefinition for same_scope_variable = same_scope_variable2

After the scope and initial value of v is defined, you can only read the address it points to in run-time, but you can change the value the pointed address holds, by dereferencing.

#6 int const * const v;

Reads as v is a constant pointer to a constant integer. That is, the value v holds is a read-only address that points to a read-only integer. Its more usual to see that as a function argument when you want to be sure the method cannot change neither the address v holds nor the value it dereferences.

int const same_scope_k  = 0xFFFFFFFF; 
int const same_scope_k2  = 0xF0FFFFFF; 
int const * const v; //declaration
v = &same_scope_k; //defined, read-only
v = &same_scope_k2; //error wont compile
*v = same_scope_k2; //error wont compile

The code below should compile with no warnings. It is on a PC, therefore memory addresses have 8 bytes

#include <stdio.h>
int main()
{
    int my_variable = 0x30; 
    int const my_constant = 0x60;
    //#1 defined and declared v 
    int v = 0x05; 
    
    //#2 defined and declared read-only const
    int const v_k = 0x10; 
    int const v_k2 = 0x11;
    
    //#3 defined and declared v_ptr as the address of v
    int *v_ptr = &v; 
    
    //#4 declared and defined this as a pointer to a constant 
    int const *v_ptr_to_k = &v_k; 
    
    //#5 declared and defined this as a constant pointer to an variable integer
    int * const v_k_ptr = &my_variable; 
    
    //#6
    //declared and defined this as a constant pointer to a constant integer
    int const * const v_k_ptr_k = &my_constant;  
    // operations 
    // change v
    printf("v has the value %x, and v_ptr is %p\n\r", *v_ptr, v_ptr);
    v = 0x80;
    printf("v has now the value %x, and v_ptr is %p\n\r", *v_ptr, v_ptr);
    
    // changing v_ptr
    v_ptr = &my_variable;
    printf("v_ptr dereferences to value %x, and v_ptr is %p\n\r", *v_ptr, v_ptr);
    //change pointer to a constant
    printf("v_ptr_to_k dereferences to value %x, and v_ptr_to_k is %p\n\r", *v_ptr_to_k, (unsigned long int *)v_ptr_to_k);
    v_ptr_to_k = &v_k2;
    printf("v_ptr_to_k dereferences to value %x, and v_ptr_to_k is %p\n\r", *v_ptr_to_k, (unsigned long int *)v_ptr_to_k);
    //*v_ptr_to_k = 0x08; //<== not allowed!
    
    //operating with a constant pointer
    printf("v_k_ptr dereferences to the value %x, and v_k_ptr is %p\n\r", *v_k_ptr, (unsigned long int *)v_k_ptr);
    v = 0x35;
    *v_k_ptr = v;
    printf("v_k_ptr dereferences to the value %x, and v_k_ptr is %p\n\r", *v_k_ptr, (unsigned long int *)v_k_ptr);
    
    //operating with a constant pointer to a constant integer
    printf("v_k_ptr_k dereferences to the value %x, and v_k_ptr_k is %p\n\r", *v_k_ptr_k, (unsigned long int *)v_k_ptr_k);
    //*v_k_ptr_k = 0x92; <== not allowed!
    //v_k_ptr_k = &my_constant; <== not allowed!
    return 0;
}

Output:

(Erratum: in the printf above v_ptr_to_k was mentioned as v_ptr_k but the variable declared and defined on the code is v_ptr_to_k.)

[blog] Good reads for free #1

I just ran into this awesome book, FPGA-Based Prototyping Methodology Manual

«The FPGA-Based Prototyping Methodology Manual: Best practices in Design-for-Prototyping(FPMM) is a comprehensive and practical guide to using FPGAs as a platform for SoC development and verification. The manual is organized into chapters which are roughly in the same order as the tasks and decisions which are performed during an FPGA-based prototyping project. The manual can be read start-to-finish or, since the chapters are designed to stand alone, you can start reading at any point that is of current interest to you.

The main lesson of the FPGA-based prototyping methodology manual might be to tackle complexity one step at a time but make sure that each step is in the right direction and not into a dead end. When starting an FPGA-based prototyping project, our success will come from a combination of preparation and effort; the more we have of the former, the less we should need of the latter.” —- Doug Amos, Austin Lesea, René Richter»

You can download it for free, with a corporate email account:

[blog] Group working

Group working: even though they perform alone in the pool, the overall result is what matters. In a pretty well balanced team, like this, each swimmer can go for his best style. If the team was heavily unbalanced, at the limit, for instance, Adrian happens to be competititve only on butterfly – Phelps would have to give up his best stroke for the overall goal – since Phelps’ crawl would deliver at least enough contribution for a medal.

During my career I have had the opportunity to work with different people, from different cultures (5 cities, 3 countries) and I think I can talk about my very own impressions of what is a functional working group. Nothing I state here can be formally proved, and are only opinions.

I believe in a very clear concept when working in group: if you can provide what others need – do it, as soon as you can. I am not saying you need to sacrifice yourself, but the overall result is more important than your very own result, as in any system. Frustrated colleagues will, even if they try to avoid, create a frustrating environment, and that is language – not a mystical energy as one could suggest. The size of your RAM memory does not mean too much if the throughput is damaged at a certain frequency.

Human language is such a complex mechanism: a biopsychosocial product from the structure of your bones, passing through the consequences of the most joyful or painful events you went through and the positions you someway have occupied on the groups you once belonged or still belong to (family, school, sports, etc.). And of course, everyone has different bones and a life story, therefore, different ways to communicate. By communication, I mean transferring, receiving and processing information. This is even more clear when working with people from different cultures.

Back to the point about the virtuous circle, it is also a mechanism: being helpful makes who helps feel fine – mainly if recognized. Being helped makes people feel included, and not apart or ignored. An ideal system has fully functional decoupled components that communicate well. No noise, no jitters, no heavy dependence between them, but if one component malfunctions/fails, the overall system will eventually malfunctions/fails, otherwise it is not a system at all.

The tricky thing in all of this is the balance1. There will be times when a person will need to provide more than receive, and another times, this very same person will need to receive more than provide. This sending+receiving individual addend, should integrate in time to an ideal value, as a contribution to the ideal system value, i.e, a goal. It seems the value for the overall system is more meaningful and easier to assess than the value for each component, but the stability of the system depends on the harmony between the components. And there are deadlocks: helpless people cannot help. And the capacity of anyone to help is also limited. If someone is not receiving, it is very probable he will not be able to provide. What comes first? That is the tricky balance.

But, there are some behavioural points I believe can help to create a balance, so this value converges – (I am assuming here the components are compatible enough, that is, it is possible to build a functional system with them)

  • do not be too proud or too humble about your competences or achievements. «the brighter the flame the quicker it burns, but ashes do not make a fireplace.» (I think it is from a Metallica song)
  • understand that everyone has theirs own merits for being at the very same place you work too
  • protect your peers, take them off awkward situations if you can; at least avoid exposing them. more clearly: do not point fingers.
  • improve your coping mechanisms to deal with frustration
  • express frustration or satisfaction with serenity: do not overreact
  • listen up to whoever wants to talk to you: and make sure you got the message.
  • be straight: irony can be funny or even tempting sometimes, but ironic communication is failed by default – at the extreme it means the opposite of what it describes and nobody is obligated to understand what is not said (I myself was tempted to write some funny (at least to me) ironic stuff on these bulets. I did not, because I am trying to be as clear as possible, as this text must have a professional tone.)
  • when communicating by virtual chats it is even more important to be straight
  • understand others people genuine voice tone. some might always sound angry to you. some might always sound happy. but that is just one element of this complex thing called human language.
  • measure your words. they have an impact. there is not a universal standard to sound understandable. but there is a universal way to not sound disrespectful.
  • do not refrain from saying anything that you do think will contribute.
  • refrain from saying things that you know will not contribute
  • understand that there are no stupid questions. for real. it is language, again
  • do not be sorry for not knowing
  • do not be proud for knowing
  • keep learning the overall system. how it works, how it fails

1 There are different timings for each component, due to different processing times, in such a way if people could be completely modeled for different situations, we could foresee worst and best cases in this flow, so we would be like a real-time system. But we are not that predictable, although being predictable is an essential good social adaptive response.

[blog] O livro

Se nos primeiros anos na escola eu normalmente queria aprender tudo que os professores também queriam ensinar, na adolescência não lembro de nada exposto no quadro com giz a que eu não tenha sido resistente, e eu ocupava mais tempo aprendendo tudo o que podia sobre como funcionavam computadores, até o dia que um livro caiu em minhas mãos. O livro chamava-se Conceitos Fundamentais da Matemática de Bento Jesus de Caraça, um matemático português, por acaso, e falo do livro mais adiante.

A Matemática no ensino médio (ou liceu, em Portugal) me intrigava. O método utilizado, hoje julgo inadequado: apostilas altamente resumidas, receitas de bolo, pouca ou nenhuma fundamentação, pano de fundo histórico ou apelo estético. Lembro-me que no primeiro ano, quando introduziram “Funções” eu pude imediatamente fazer um paralelo com as funções dos pequenos programas que já fazia no meu PC, e além disso, utilizávamos um livro didático (Bongiornno), em que o autor sempre fazia questão de construir a matemática pura, além de definir conceitos com palavras. A coisa fluiu bem.

No segundo ano a trigonometria sai do triângulo retângulo e vai para o ciclo trigonométrico. Por que o professor não desenhava aquele ciclo no plano cartesiano4 até hoje eu não sei. Também sei que teria sido muito importante alguém ter nos dito que um ponto não tinha dimensão para eu poder entender a tangente. Radianos… como eles podiam valer o mesmo para um arco de 1mm e de 1km? Por qual razão pi radianos são 180 graus? O Binômio de Newton veio ao mundo pelo mesmo motivo que rabanetes?

Estas coisa ocorriam-me, e notem que são perguntas que todos podem perceber, mas que não são fundamentais para a metodologia de ensino tecnicista, assim não constavam nas apostilas que nos preparavam para o que faziam parecer a barreira que ia diferenciar os vencedores dos perdedores: o vestibular. O professor também não as mencionava, e então pensava eu que estava a perder algo muito óbvio. O fato é: o mundo é material e assim é nossa consciência primária, e é necessário que alguém conscientemente nos conduza ao plano das ideias que é onde reside a Matemática Pura, onde não há dogmas, mas abstrações fundamentadas. Esta condução, só pode ser feita a contento, se partirmos de uma perspectiva Materialista – porque esta já é natural a qualquer a pessoa.

O drama1: eu não tinha idade o suficiente para ser adulto, mas precisava escolher minha profissão. Eu queria ser engenheiro ou equivalente, mas como raios eu não era interessado naquilo que apresentavam-me como sendo Matemática? Física tampouco. Se assim o fosse, cursar uma eventual faculdade de engenharia seria um suplício. Mas eu estava sendo treinado para ser uma calculadora científica: passavam-me instruções e informações, e como processá-las, sem fundamentação, de forma dogmática. Creio no entanto, que tentavam ser os melhores professores que podiam ser e seguiam um método que julgavam adequado para que pudéssemos passar nos vestibulares.

«Vem lamber ferida...» era o mnemônico para velocidade = comprimento de onda x frequência. Será mesmo que era impossível explicar a fórmula para ninguém ter que decorá-la, muito menos associá-la a este convite inusitado?

Até que chega-me em mãos o livro mencionado anteriormente. Primeiro o autor ensina-nos a contar. Sim, exatamente: o desenho de uma bolinha associada ao símbolo da unidade: 1. Depois 2, 3… muitos. Aí ele estava a nos mostrar um dos pilares do pensamento matemático: a relação entre entidades, reais, imaginárias ou qualquer combinação das duas e seus símbolos. O livro mostra o que é Matemática, e os problemas de que os matemáticos se ocupam

Pitágoras, Platão, Parménides e as boas e más consequências de suas ideias. Zenão e seu paradoxo: como pode o atleta (não) ultrapassar a tartaruga? Está lançada a dúvida para questionarmos a natureza dos números, e aberto o caminho para desejarmos pensar sobre continuidade e infinitésimos, que são apresentados na última parte da obra.

Antes somos apresentados às funções, inclusive às trigonométricas. Aos algebristas e ao algebrismo. O número imaginário, como um belo exemplo do elo entre a abstração e a solução de polinômios que modelam a materialidade. Diferenciava a técnica do tecnicismo.

«Um ponto é aquilo que não tem partes e uma linha é um comprimento sem largura2.» E eu pude finalmente compreender a tangente. A premissa necessária para ser verdade que seja possível existir retas que ao cruzarem com curvas possam interceptar um, e somente um ponto desta curva, retirou a minha hesitação e criou interesse pelo assunto. É a consciente condução à Matemática Pura – que eu destaco como a maior virtude do livro. No tempo presente só é possível sair do lugar que já estamos ou que nos é consciente.3

1 O livro é de 1941. Eu o descobri em 2001.

2 Como definiu Euclides, em “Os elementos”. Teria sido bom nos contar que a geometria era uma ciência de agrimensores na sua época, e daí a necessidade de abstração dos “elementos” e sua formalização como disciplina.

3 esta também é uma possível reflexão sobre Paradoxo de Zenão. O autor também utiliza o conceito filosófico do “Devir”, em linguagem simples, para nos apresentar a continuidade.

4 Isto ajudaria de pronto a entender a construção (representação geométrica) da unidade imaginária, que foi apresentada mais adiante quando aprendemos a encontrar raízes de polinômios de qualquer grau no campo Complexo. Apesar de chamarmos de unidade imaginária por ser representada como algo “absurdo” que é a raiz quadrada da unidade Real negativa, não é preciso mais que uma tabela e alguns pontos para visualizá-la geometricamente, na lei y = x^2+1, quando x = 0. Depois de visualizado que a unidade imaginária é o segmento de reta real O1 com ângulo de 90 graus, a identidade que representa um número complexo de tamanho |z|, z = |z|*(cos(angulo) + i*sen*(angulo)) é a tradução natural da construção geométrica, e não precisará ser decorada. Assim, finalmente elucidando-se que estamos em um novo espaço métrico, além da reta numérica real, cujo a métrica é bidimensional, e tem álgebra apropriada para calcular símbolos que carregam dois valores – aproveitando-se da trigonometria e um novo elemento que mostrou-se útil (“i”) – mais uma condução consciente à Matemática Pura foi feita. Por isso que Bento começa o livro nos “ensinando” a contar, a condução mais primitiva ao pensamento matemático.

[blog] NASA’s Ten Principles of Safety-Critical Code

These are the NASAs ten principles for safety-critical code. It is interesting to note that they were published later than MISRA-C that already covers it naturally.

  1. Restrict all code to very simple control flow constructs, do not use goto statements, setjmp or longjmp constructs, direct or indirect recursion.
  2. Give all loops a fixed upper bound. It must be trivially possible for a checking tool to prove statically that the loop cannot exceed a preset upper bound on the number of iterations. If a tool cannot prove the loop bound statically, the rule is considered violated.
  3. Do not use dynamic memory allocation after initialization.
  4. No function should be longer than what can be printed on a single sheet of paper in a standard format with one line per statement and one line per declaration. Typically, this means no more than about 60 lines of code per function.
  5. The code’s assertion density should average to minimally two assertions per function. Assertions must be used to check for anomalous conditions that should never happen in real-life executions. Assertions must be side effect-free and should be defined as Boolean tests. When an assertion fails, an explicit recovery action must be taken, such as returning an error condition to the caller of the function that executes the failing assertion. Any assertion for which a static checking tool can prove that it can never fail or never hold violates this rule.
  6. Declare all data objects at the smallest possible level of scope.
  7. Each calling function must check the return value of non-void functions, and each called function must check the validity of all parameters provided by the caller.
  8. The use of the preprocessor must be limited to the inclusion of header files and simple macro definitions. Token pasting, variable argument lists (ellipses), and recursive macro calls are not allowed. All macros must expand into complete syntactic units. The use of conditional compilation directives must be kept to a minimum.
  9. The use of pointers must be restricted. Specifically, no more than one level of dereferencing should be used. Pointer dereference operations may not be hidden in macro definitions or inside typedef declarations. Function pointers are not permitted.
  10. All code must be compiled, from the first day of development, with all compiler warnings enabled at the most pedantic setting available. All code must compile without warnings. All code must also be checked daily with at least one, but preferably more than one, strong static source code analyzer and should pass all analyses with zero warnings.