Arquivo da categoria: Computação / Computing

E o Vento Levou… a Microsoft

As coisas definitivamente não andam boas para Steve Ballmer, CEO da Microsoft. Começando por subestimar o potencial do iPhone às suas, digamos, performances, sua gestão tem decaído em um bom número de apostas equivocadas. Por causa delas, hoje, a Apple, outrora falida, vale aproximadamente duas Microsoft (para a minha alegria pessoal), desbancando-a como como um velho ícone de uma já superada era PC. Espera-se que agora Ballmer reverta esse quadro pelo lançamento do Windows Phone Mango e do Windows 8 ambos com a Interface Metro. Porém, aparentemente, nem mesmo a Metro deixará o barco Microsoft de fazer água.
 
Uma nova antiga idéia

Inspirados no lançamento do Sistema Operacional Mac OS X da Apple, os sistemas operacionais de vários dispositivos computacionais lançaram-se numa corrida de design, a fim de oferecer a mais bela, colorida e interessante interação gráfica para o usuário. Isso afetou profundamente o design de softwares portáteis, tais como os celulares, de modo que, entre eles, foi possível evoluir de um Siemens A50 para um Samsung Galaxy S II. A Microsoft, vendo a sua participação absoluta no mercado de computadores cair diante do iOS da Apple e do Android da Google, lançou o seu próprio conceito de design para  os sistemas operacionais portáteis, a Metro. E eis buraco do barco.

Sem dúvida nenhuma, por se tratar de uma nova interface, a Metro atrairá interessados e compradores. Tudo o que é novo chama a atenção e por isso a Nokia, uma das maiores apostadoras desse conceito da Microsoft, lançou a sua linha de celulares Lumnia. A Nokia reinava absoluta no mercado de smartphones até a entrada da Google e da Apple e o Lumnia representa uma grande esperança de reviravolta para ela. Talvez a última, antes dela ser adquirida pela Microsoft ou pela Amazon.

Mas, vendo a Metro sem afobação, percebe-se que ela representa um retrocesso no design alcançado até o presente. A Metro é essencialmente bicolor com ícones bidimensionais brancos. Não fossem as distrações de algumas fotos em seus quadros, ela seria terrivelmente enfadonha, tal como a Tela de Configurações do Xbox 360 nessa interface. Na verdade, os seus ícones são similares às da Samsung F700 antes do advento do iPhone – por esse e por outros motivos, aliás, a Samsung é processada pela Apple, pois ela coincidentemente mudou esses ícones depois do iPhone, redesenhando muitos deles iguais aos do iOS. Ocorre que até a Samsung percebeu que esses ícones brancos e bidimensionais não são atrativos e, não se sabe bem o porquê, a Microsoft, em pleno campeonato, pensa que eles são uma evolução.

Confundindo integração com padronização
 
A Metro tem o mérito de ser uma excelente interface para touchscreen, pois foi desenhada para isso. Então seria um erro colocá-la num computador com mouse e teclado, certo? Não para a Microsoft. E esse é justamente o motivo pelo qual o Windows 8 é torpedeado pela crítica. Porque, diferentemente de suas concorrentes, que tomam o cuidado de oferecer uma interface adequada para cada dispositivo computacional, com uma integração limitada entre eles, a Microsoft deseja que todos os dispositivos rodem sob a Metro. Ela o quer porque isso maximizaria a portabilidade de seus aplicativos. Porém não é comum que os computadores Windows tenham emuladores de touchscreen tais como o Magic Mouse e o Trackpad da Apple. Pobres usuários da Metro, que terão que repetidamente segurar, arrastar e soltar com os seus mouses cada tela da interface! Se você tiver lesões musculares, prepare o seu anti-inflamatório! Por isso, padronizar interfaces sem padronizar o hardware é tolice. Por isso, a Apple não produziu nada semelhante ao Kinect para os seus computadores. Simplesmente porque, a menos que você seja um gamer entusiasmado, não é legal cansar as suas mãos de usar o computador quando ainda faltam muitas horas para terminar o seu expediente de trabalho.

Mas, enfim, o tempo é o melhor dos críticos. Vejamos se a Microsoft terá sucesso em adentrar para o  mercado de smartphones tal como ela adentrou retumbante para o mercado de consoles de games que, aliás, ganhou um novo concorrente: o New iPad, o console não oficial da Apple. Por hora, porém, parece-me que a batata do Steve Ballmer está assando.

Anúncios

CÓDIGO: Calendário Gregoriano Feito em Java

Abaixo um código feito em Java (para o Java SE 7) que manipula um calendário gregoriano simples, assumindo que se quer retornar o resultado para um campo texto de nome “txData” tipo JTextField. Esse campo pertence a uma outra janela qualquer:

[sourcecode language="java"]
import java.util.*;
import java.text.*;
public class CalendarioUI extends javax.swing.JFrame {
    private javax.swing.JTextField txData;
    
    /**
     * Creates new form CalendarioUI
     */
    public CalendarioUI() {
        initComponents();
        this.setLocationRelativeTo(null);
        this.txData = null;       
    }
    
    public void setCampoData(javax.swing.JTextField txData) {
        this.txData = txData;
        /**
         * Aqui, eu suponho que voce queira informar
         * a data selecionada do calendario a
         * um campo JTextField de uma outra janela
         */
    }
    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    private void initComponents() {
        btAnt = new javax.swing.JButton();
        txPeriodo = new javax.swing.JTextField();
        btProx = new javax.swing.JButton();
        spCalendario = new javax.swing.JScrollPane();
        tbCalendario = new javax.swing.JTable();
        btOK = new javax.swing.JButton();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Calendário");
        setAlwaysOnTop(true);
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        setName("frCalendario");
        setResizable(false);
        setType(java.awt.Window.Type.UTILITY);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });
        btAnt.setText("«");
        btAnt.setToolTipText("");
        btAnt.setName("");
        btAnt.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btAntActionPerformed(evt);
            }
        });
        btAnt.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                btAntKeyReleased(evt);
            }
        });
        txPeriodo.setEditable(false);
        txPeriodo.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        txPeriodo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                txPeriodoActionPerformed(evt);
            }
        });
        btProx.setText("»");
        btProx.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btProxActionPerformed(evt);
            }
        });
        btProx.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                btProxKeyReleased(evt);
            }
        });
        spCalendario.setBackground(new java.awt.Color(255, 255, 255));
        spCalendario.setBorder(null);
        tbCalendario.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null}
            },
            new String [] {
                "D", "S", "T", "Q", "Q", "S", "S"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.Integer.class, java.lang.Integer.class,
                java.lang.Integer.class, java.lang.Integer.class,
                java.lang.Integer.class, java.lang.Integer.class,
                java.lang.Integer.class
            };
            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        tbCalendario.setCellSelectionEnabled(true);
        tbCalendario.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                tbCalendarioMouseClicked(evt);
            }
        });
        tbCalendario.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                tbCalendarioKeyReleased(evt);
            }
        });
        spCalendario.setViewportView(tbCalendario);
        btOK.setText("OK");
        btOK.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btOKMouseClicked(evt);
            }
        });
        btOK.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                btOKKeyReleased(evt);
            }
        });
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout
  (getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(15, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
   layout.createSequentialGroup()
                        .addComponent(btAnt)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txPeriodo, javax.swing.GroupLayout.PREFERRED_SIZE, 165,
   javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btProx)
                        .addGap(70, 70, 70))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(btOK)
                        .addContainerGap())
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
   layout.createSequentialGroup()
                        .addComponent(spCalendario, javax.swing.GroupLayout.PREFERRED_SIZE,
   375, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(txPeriodo, javax.swing.GroupLayout.PREFERRED_SIZE,                      javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btProx)
                    .addComponent(btAnt))
                .addGap(18, 18, 18)
                .addComponent(spCalendario, javax.swing.GroupLayout.PREFERRED_SIZE, 123,
  javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(btOK)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pack();
    }//                        
    private String substitui () {
        String dtJDBC = this.txPeriodo.getText().toUpperCase();
        dtJDBC = dtJDBC.replaceAll("JAN", "01");
        dtJDBC = dtJDBC.replaceAll("FEV", "02");
        dtJDBC = dtJDBC.replaceAll("MAR", "03");
        dtJDBC = dtJDBC.replaceAll("ABR", "04");
        dtJDBC = dtJDBC.replaceAll("MAI", "05");
        dtJDBC = dtJDBC.replaceAll("JUN", "06");
        dtJDBC = dtJDBC.replaceAll("JUL", "07");
        dtJDBC = dtJDBC.replaceAll("AGO", "08");
        dtJDBC = dtJDBC.replaceAll("SET", "09");
        dtJDBC = dtJDBC.replaceAll("OUT", "10");
        dtJDBC = dtJDBC.replaceAll("NOV", "11");
        dtJDBC = dtJDBC.replaceAll("DEZ", "12");
        return dtJDBC;
    }
    
    private Date converte() throws Exception {
        String dtJDBC = this.substitui();
        dtJDBC = new String ("01/").concat(dtJDBC);
        DateFormat format = DateFormat.getDateInstance();
        return format.parse(dtJDBC.concat(" 0:0 AM"));
    }
    
    private void preenche(GregorianCalendar perGreg) throws Exception {
        int i, diasMes = perGreg.getActualMaximum(Calendar.DATE);
        int col = 0;
        int lin = 0;
        for (i = 0; i < 42; i++)
        {
            this.tbCalendario.setValueAt("",lin,col++);               
            if (col == 7) {
                col = 0;
                ++lin;
            }
        }              
        
        col = perGreg.get(perGreg.DAY_OF_WEEK) - 1;
        lin = 0;
        
        for (i = 0; i < diasMes; i++)
        {
            this.tbCalendario.setValueAt(String.valueOf(i + 1),lin,col++);               
            if (col == 7) {
                col = 0;
                ++lin;
            }
        }       
    }
    
    private void formWindowOpened(java.awt.event.WindowEvent evt) {                                 
        
        SimpleDateFormat formatoPer = new
                SimpleDateFormat ("MMM/yyyy");
        Date hoje = new Date(System.currentTimeMillis());
        this.txPeriodo.setText(formatoPer.format(hoje));
        try
        {
            GregorianCalendar perGreg = new GregorianCalendar();
            perGreg.setTime(this.converte());
            this.preenche(perGreg);
        }
        catch (Exception e)
        { e.printStackTrace(); }
    }                                
    private void soma(boolean incrementa) {
        try
        {
            GregorianCalendar perGreg = new GregorianCalendar();
            perGreg.setTime(this.converte());
            if (!incrementa)
                perGreg.add(perGreg.MONTH, -1);
            else
                perGreg.add(perGreg.MONTH, 1);
            this.preenche(perGreg);
            SimpleDateFormat formatoPer = new
                    SimpleDateFormat ("MMM/yyyy");
            this.txPeriodo.setText(formatoPer.format(perGreg.getTime()));
        } catch (Exception e) {e.printStackTrace();}       
    }
    
    private void txPeriodoActionPerformed(java.awt.event.ActionEvent evt) {                                         
        
    }                                        
    private void btAntActionPerformed(java.awt.event.ActionEvent evt) {                                     
        
        this.soma(false);
    }                                    
    private void btProxActionPerformed(java.awt.event.ActionEvent evt) {                                      
        
        this.soma(true);
    }                                     
    private void tbCalendarioMouseClicked(java.awt.event.MouseEvent evt) {                                         
        
        this.gera();
    }                                        
    private void tbCalendarioKeyReleased(java.awt.event.KeyEvent evt) {                                        
        
        this.gera();
    }                                       
    private void btOKMouseClicked(java.awt.event.MouseEvent evt) {                                 
        
        this.setVisible(false);
    }                                
    private void btOKKeyReleased(java.awt.event.KeyEvent evt) {                                
        
        if (evt.getKeyCode() != evt.VK_ENTER &&
            evt.getKeyCode() != evt.VK_SPACE) return;
            this.setVisible(false);       
    }                               
    private void btAntKeyReleased(java.awt.event.KeyEvent evt) {                                 
        if (evt.getKeyCode() != evt.VK_ENTER &&
            evt.getKeyCode() != evt.VK_SPACE) return;
        this.soma(false);       
        
    }                                
    private void btProxKeyReleased(java.awt.event.KeyEvent evt) {                                  
        if (evt.getKeyCode() != evt.VK_ENTER &&
            evt.getKeyCode() != evt.VK_SPACE) return;
        this.soma(true);       
    }                                 
    private void gera() {
        int lin, col;       
        if (tbCalendario.getSelectedRowCount() > 1 ||
                tbCalendario.getSelectedColumnCount() > 1)
            tbCalendario.clearSelection();
        if (tbCalendario.getSelectedRowCount() == 0 &&
                tbCalendario.getSelectedColumnCount() == 0)
            this.txData.setText("");
       lin = tbCalendario.getSelectedRow();
       col = tbCalendario.getSelectedColumn();
       if (lin < 0 || col < 0)
           this.txData.setText("");
       String dtJDBC = (String) tbCalendario.getValueAt(lin, col);
       dtJDBC = dtJDBC.concat("/").concat(this.substitui());       
        if (dtJDBC.length() == 10)
            this.txData.setText(dtJDBC);
        else
            this.txData.setText("");
    }
    
    // Variables declaration - do not modify                    
    private javax.swing.JButton btAnt;
    private javax.swing.JButton btOK;
    private javax.swing.JButton btProx;
    private javax.swing.JScrollPane spCalendario;
    private javax.swing.JTable tbCalendario;
    private javax.swing.JTextField txPeriodo;
    // End of variables declaration                  
}
[/sourcecode]

CÓDIGO: Escrever um Número por Extenso

O programa abaixo, escrito para Visual Basic, fornece um método para receber um número em formato contábil #,00 e retorna o seu significado por extenso através da função Moeda(Numero); ou, se o programador preferir, através da função Porcentagem(Numero). Ambas recebem e retornam um tipo String.

 


Function Conectivo(ByVal Numero As Integer, ByVal Termo As String) As String
    Dim Result As String
    If Numero = 0 Then
        Result = ""
    ElseIf Termo = "" Then
        Result = ""
    Else
        Result = " E "
    End If
    Conectivo = Result
End Function 

Function Unidade(ByVal Numero As String) As String
    Dim Aux As String, Result As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Right(Numero, 1) 

    Select Case CInt(Aux)
        Case 1
            Result = "UM"
        Case 2
            Result = "DOIS"
        Case 3
            Result = "TRES"
        Case 4
            Result = "QUATRO"
        Case 5
            Result = "CINCO"
        Case 6
            Result = "SEIS"
        Case 7
            Result = "SETE"
        Case 8
            Result = "OITO"
        Case 9
            Result = "NOVE"
        Case Else
            Result = ""
    End Select
    Unidade = Result
End Function 

Function Dezena_Lote10(ByVal Numero As String) As String 

    Dim Aux As String, Result As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Right(Numero, 2) 

    Select Case CInt(Aux)
        Case 11
            Result = "ONZE"
        Case 12
            Result = "DOZE"
        Case 13
            Result = "TREZE"
        Case 14
            Result = "CATORZE"
        Case 15
            Result = "QUINZE"
        Case 16
            Result = "DEZESSEIS"
        Case 17
            Result = "DEZESSETE"
        Case 18
            Result = "DEZOITO"
        Case 19
            Result = "DEZENOVE"
        Case Else
            Result = "DEZ"
    End Select 

    Dezena_Lote10 = Result
End Function 

Function Dezena(ByVal Numero As String) As String 

    Dim Aux As String, Result As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Right(Numero, 2) 

    If CInt(Aux) <> 10 Then
        Aux = Left(Aux, 1)
        Select Case CInt(Aux)
            Case 1
                Result = Dezena_Lote10(Numero)
            Case 2
                Result = "VINTE" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 3
                Result = "TRINTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 4
                Result = "QUARENTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 5
                Result = "CINQUENTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 6
                Result = "SESSENTA" & _
               Conectivo(CInt(Aux), Unidade(Numero)) & _
               Unidade(Numero)
            Case 7
                Result = "SETENTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 8
                Result = "OITENTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case 9
                Result = "NOVENTA" & _
                Conectivo(CInt(Aux), Unidade(Numero)) & _
                Unidade(Numero)
            Case Else
                Result = "" & Unidade(Numero)
        End Select
    Else
        Result = "DEZ"
    End If
    Dezena = Result
End Function 

Function Centena(ByVal Numero As String) As String
    Dim Aux As String, Result As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Right(Numero, 3) 

    If CInt(Aux) <> 100 Then
        Aux = Left(Aux, 1)
        Select Case CInt(Aux)
            Case 1
                Result = "CENTO" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 2
                Result = "DUZENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 3
                Result = "TREZENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 4
                Result = "QUATROCENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 5
                Result = "QUINHENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 6
                Result = "SEISCENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 7
                Result = "SETECENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 8
                Result = "OITOCENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case 9
                Result = "NOVECENTOS" & _
                Conectivo(CInt(Aux), Dezena(Numero)) & _
                Dezena(Numero)
            Case Else
                Result = Dezena(Numero)
        End Select
    Else
        Result = "CEM"
    End If
    Centena = Result
End Function 

Function CentenaMilhar(ByVal Numero As String) As String
    Dim Result As String, Aux As String, Conjuncao As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Numero
    If Centena(Right(Aux, 3)) = "" And Len(Aux) > 3 Then
        Conjuncao = ""
    Else
        Conjuncao = "E "
    End If 

    Select Case Len(Aux)
        Case 1
            Result = Unidade(Aux)
        Case 2
            Result = Dezena(Aux)
        Case 3
            Result = Centena(Aux)
        Case 4
            Result = Unidade(Left(Aux, 1)) & " MIL " & _
        Conjuncao & Centena(Aux)
        Case 5
            Result = Dezena(Left(Aux, 2)) & " MIL " & _
            Conjuncao & Centena(Aux)
        Case 6
            Result = Centena(Left(Aux, 3)) & " MIL " & _
            Conjuncao & Centena(Aux)
        Case Else
            Result = ""
    End Select
    CentenaMilhar = Result
End Function 

Function CentenaMilhao(ByVal Numero As String) As String
    Dim Result As String, Aux As String
    Numero = CStr(CInt(Trim(Numero)))
    Aux = Numero
    Select Case Len(Aux)
        Case 7
            If CInt(Left(Aux, 1)) = 1 Then
                Result = Unidade(Left(Aux, 1)) & _
                " MILHAO " & CentenaMilhar(Right(Aux, 6))
            Else
                Result = Unidade(Left(Aux, 1)) & _
                " MILHOES " & CentenaMilhar(Right(Aux, 6))
            End If
        Case 8
            Result = Dezena(Left(Aux, 2)) & _
            " MILHOES " & CentenaMilhar(Right(Aux, 6))
        Case 9
            Result = Centena(Left(Aux, 3)) & _
            " MILHOES " & CentenaMilhar(Right(Aux, 6))
        Case Else
            Result = CentenaMilhar(Aux)
    End Select
    CentenaMilhao = Result
End Function 

Function Moeda(ByVal Numero As String) As String
    Dim Result As String, Direito As String, M_Direito As String
    Dim Esquerdo As String, M_Esquerdo As String
    Dim Teste As Boolean
    Numero = Trim(Numero)
    If Len(Numero) < 3 Then
        Result = "NULL"
    Else
        Result = ""
        Direito = CStr(CInt(Right(Numero, 2)))
        Esquerdo = CStr(CInt(Left(Numero, Len(Numero) – 3))) 

        If CInt(Esquerdo) = 1 Then
            M_Esquerdo = " REAL"
        ElseIf CInt(Esquerdo) = 0 Then
            M_Esquerdo = " "
        Else
           Teste = CInt(Left(Esquerdo, 1)) = 1 And _
           CInt(Right(Esquerdo, Len(Esquerdo) – 1)) = 0
           Teste = Teste And Len(Esquerdo) > 6
            If Teste Then
                M_Esquerdo = " DE"
            Else
                M_Esquerdo = ""
            End If
                M_Esquerdo = M_Esquerdo & " REAIS" 

        End If 

        If CInt(Direito) = 1 Then
            M_Direito = " CENTAVO"
        ElseIf CInt(Direito) = 0 Then
            M_Direito = " "
        Else
            M_Direito = " CENTAVOS"
        End If 

        If CentenaMilhao(Esquerdo) <> "" Then
            Result = CentenaMilhao(Esquerdo) & M_Esquerdo
        End If 

        If CentenaMilhao(Direito) <> "" Then
            If Result = "" Then
                Result = CentenaMilhao(Direito) & M_Direito
            Else
                Result = Result & " E " & _
                CentenaMilhao(Direito) & M_Direito
            End If
        End If
    End If
    Moeda = Result
End Function 

Function Porcentagem(ByVal Numero As String) As String
    Dim Result As String, Direito As String, M_Direito As String
    Dim Esquerdo As String, M_Esquerdo As String, Conjuncao As String 

    Numero = Trim(Numero)
    Result = ""
    Esquerdo = ""
    Direito = ""
    M_Esquerdo = ""
    Conjuncao = "" 

    If Len(Numero) < 3 Then
        Result = "NULL"
    Else
        Direito = Right(Numero, 2)
        Esquerdo = CStr(CInt(Left(Numero, Len(Numero) – 3)))
        If CInt(Esquerdo) = 0 Then
            M_Esquerdo = " ZERO PORCENTO"
        Else
            M_Esquerdo = " PORCENTO"
        End If
    End If 

    If CInt(Direito) = 0 Then
        M_Direito = ""
   ElseIf CInt(Left(Direito, 1)) > 0 And _
          CInt(Right(Direito, 1)) = 0 Then
        Direito = Left(Direito, 1)
        Conjuncao = " E "
        M_Direito = " DECIMO"
        If CInt(Left(Direito, 1)) > 1 Then
            M_Direito = M_Direito & "S"
        End If
    Else
        Conjuncao = " E "
        M_Direito = " CENTESIMO"
        If CInt(Direito) > 1 Then
            M_Direito = M_Direito & "S"
        End If
    End If
    Result = CentenaMilhao(Esquerdo) & M_Esquerdo & _
    Conjuncao & CentenaMilhao(Direito) & M_Direito
    Porcentagem = Result
End Function


ALGORITMOS: O Barbeiro Dorminhoco

Dando sequência ao nosso estudo em programação concorrente, apressentamos esse desafio.

O Problema do Barbeiro Dorminhoco consiste no seguinte: um barbeiro possui uma barbearia que funciona em horário comercial. Se nenhum cliente aparece, o barbeiro tira um cochilo. Se há clientes sentados nas cadeiras, o barbeiro atende por ordem de chegada. Se um cliente chega na barbearia e encontra as cadeiras lotadas, vai embora. Se um cliente chega na barbearia e encontra o barbeiro dormindo, ele o acorda.

O algoritmo pode ser descrito conforme abaixo. O método inicia indica processamento concorrente.

1. Programa Principal

   …

   Barbeiro.inicia ( )
   Cliente.inicia ( )

2. Barbeiro.inicia ( … )

   enquanto Barbearia.aberta ( )
   {
      Se Clientes.quantidade ( ) = 0
      {
         dorme ( )
      } senão {
         Se Não atendendo ( )
         {
            Clientes.getMutex ( ).lock ( )
            Cliente = Clientes.dequeue ( )
            Clientes.getMutex ( ).unlock ( )
            atende (Cliente)
         }
      }
   }

3. Cliente.inicia ( … )

   enquanto Barbearia.aberta ( )
   {
      Se Clientes.quantidade ( ) = Barbearia.capacidade ( )
      {
         sair ( )
      } senão {
         Clientes.getMutex ( ).lock ( )
         Clientes.enqueue (this)
         Clientes.getMutex ( ).unlock ( )
         Se Barbeiro.dormindo ( )
         {
            Barbeiro.acorda ( )
         }
      }
   }

ALGORITMOS: Os Leitores e os Escritores

Este problema é o segundo da nossa série de estudos em programação concorrente. Ele é uma alegoria dos problemas que os processos concorrentes enfrentam ao acessar uma área de memória compartilhada. Consiste no seguinte:

Há uma praça pública em Atenas onde, no meio da qual, os escribas anotam em uma placa pendurada num pilar as resoluções tomadas pela Assembléia do Povo. Essa placa pode ser lida por todo o povo, desde que haja o que ler; mas somente um escriba pode escrevê-la por vez. Outrossim, para que os escribas possam realizar o seu trabalho, é necessário que a aglomeração do povo ao redor da placa não os impeça de acessá-la.

Podemos então extrair os requisitos do problema, fazer algumas considerações e propor um algoritmo.

a) Um escriba por vez pode escrever na placa.

b) Cada plebeu pode lê-la simultaneamente, contanto que haja algo a ler.

c) Quando um escriba desejar escrever a placa, não estando ela sendo escrita, o povo ao redor deve afastar-se.

Como os escribas apenas recebem resoluções da Assembléia e as escrevem na placa, não precisamos nos preocupar se há um outro escriba no conjunto que tenha algo a escrever inadvertidamente. Assim, podemos imaginar os escribas organizados em uma fila. Se há uma resolução tomada, a Assembléia manda o escriba detentor da vez escrever algo. Em sequência, o escriba dá lugar a todos os outros para que possam escrever, cada um a sua vez, por ordem. É necessário perceber também que há um conjunto fixo de escribas para a Assembléia. A Assembléia, que é organizada, não haverá de contratar novos escribas no meio do processo legislativo.

Terminado o trabalho do escriba, a Assembléia convoca o povo e este lê. Com uma nova resolução a ser escrita, o povo é disperso e reconvocado depois. Repare que não precisamos nos preocupar imediatamente na leitura por cada cidadão, pois estes estão abstraídos em “povo.” O objeto “Povo” é dispersado e convocado. Este objeto é o que tratará da dispersão e convocação de cada um de seus membros.

Cada plebeu lê a placa pelo tempo que achar necessário. Isso não é um dado relevante para ser tratado.

Assim, nós temos o algoritmo seguinte em pseudocódigo orientado a objeto que segue abaixo. Repare que o método de execução paralela é Plebeu.iniciar.

1. Programa Principal

 

   enquanto Assembleia.emSessao ( )
   {
      Se Assembleia.novaResolucao ( )
      {
         Se (Povo.leitores ( ) > 0)
         {
            Povo.dispersar ( )
         }
         e = Escribas.dequeue ( )
         e.escrever ( )
         Escribas.enqueue (e)        
         Povo.convocar ( )     
      }
   }

 
2. Povo.convocar ( )

   n = 1
   enquanto (n <= quantidade ( ))
   {
      Plebeu = dequeue ( )
     
Plebeu.iniciar ( )
      enqueue (Plebeu)
      n = n + 1
   }

   enquanto (leitores ( ) < quantidade ( )) {  }

 

3. Povo.dispersar ( )

   n = 1
   enquanto (n <= quantidade ( ))
   {
      Plebeu = dequeue ( )
      Se Plebeu.lendo ( )
      {
         Plebeu.sair ( )
      }
      enqueue (Plebeu)
      n = n + 1
   }

   enquanto (leitores ( ) > 0) {  }

 

4. Plebeu.ler ( )

   lendo (verdade)
   Povo.getMutex ( ).lock( )
   Povo.adicionarLeitor ( )
   Povo.getMutex ( ).unlock ( )   
   sair ( )

 
5. Plebeu.iniciar ( )
(Plebeu herda Thread)

ler ( )
 
6. Plebeu.sair ( )

   lendo (falso)
   Povo.getMutex ( ).lock( )
   Povo.subtrairLeitor ( )
   Povo.getMutex ( ).unlock ( )

ALGORITMOS: O Jantar dos Filósofos

O Problema do Jantar dos Filósofos é um problema de programação concorrente proposto por Dijkstra em 1965 e é uma alegoria do que ocorre nos sistemas computacionais multiprocessados que disputam os mesmos recursos limitados e dependem de um algoritmo mestre ou de um sistema operacional que evite a ocorrência de conflitos entre os processos concorrentes. Consiste no seguinte:

Há cinco filósofos sentados ao redor de uma mesa sobre a qual estão cinco talheres. Diante de cada filósofo há uma refeição a comer e os talheres estão dispostos nos dois lados de cada prato de tal forma que há apenas um talher entre cada dois filósofos. Para comer, cada filósofo deve usar dois talheres. Enquanto não comem, os filósofos ficam pensando.

A exigência para a solução deste problema é a criação de um algoritmo que gerencie a janta ordeira do grupo, sem que os filósofos briguem por talheres que estão sendo utilizados.

Considerando que este problema é um problema computacional, é importante percebermos que se escolhermos arbitrariamente um filósofo para comer primeiro, podemos permitir que outro coma desde este esteja em tal posição que o primeiro escolhido não seja incomodado. Isso é fácil de conceber se imaginarmos os filósofos sentados em tal posição que suas cadeiras formem os vértices de um pentágono. Neste caso, para cada filósofo escolhido arbitrariamente, há um filósofo em posição oposta ao vértice que pode também pode comer. Considerando isso, os opostos dos vértice do ângulo agudo (o filósofo sentado na cabeceira da mesa) são os vértices dos ângulos da base (os filósofos sentados na extremidade da mesa). Se escolhêssemos o filósofo sentado na cabeceira para comer primeiro, poderíamos escolher para comer com ele um dos filósofos sentados na extremidade da mesa. Os demais esperariam pelos talheres. De semelhante forma, se escolhêssemos um dos mais próximos ao filósofo na cabeceira, o seu companheiro de janta seria aquele que está do lado oposto da mesa.

Podemos escolher dois filósofos por etapa unitária. Isso nos conduz sempre a três etapas: em duas etapas comem dois e noutra somente um. Assim uma das combinações possíveis (descrita no quadro 1 nas instâncias Th1, Th2 e Th3) segue abaixo em pseudocódigo orientado a objeto que assume o conceito de mutex. No quadro 2, reparar que VarMutex referencia Mesa; P1 referencia F1, F2 e F3 quando passados em parâmetro; idem para P2 que referencia F4 e F5. Reparar também que a classe Thread define vários tipos de parâmetros para “inicia,” cuja execução é determinada e gerenciada pelo escalonador do sistema operacional, aplicando-se o mesmo princípio para a sua sub-classe Filosofo.

1. Programa Principal

   Filosofo F1, F2, F3, F4, F5
   Talher T1, T2, T3, T4, T5
   Thread Th1, Th2, Th3
   Mutex Mesa

   .
   .
   .

   F1.associa (T1, T2)
   F2.associa (T1, T3)
   F3.associa (T3, T5)
   F4.associa (T4, T5)
   F5.associa (T2, T4)

   Th1 = cria Thread (Mesa)
   Th2 = cria Thread (Mesa)
   Th3 = cria Thread (Mesa)

   Th1.inicia (F1)
   Th2.inicia (F2, F4)
   Th3.inicia (F3, F5)

2. Th1.inicia ( … )

Th2.inicia ( … ) e Th3.inicia ( … )

   VarMutex.lock ( )
   P1.inicia ( )

   enquanto P1.ativo ( ) {
      dorme ( )
   }

   VarMutex.unlock ( )

   VarMutex.lock ( )
   P1.inicia ( )
   P2.inicia ( )

   enquanto P1.ativo ( ) ou P2.ativo ( ) {
      dorme ( )
   }

   VarMutex.unlock ( )

3. Objeto “Filósofo”  herda Thread [ Filosofo.inicia ( ) ]

      pega ( )
      come ( )
      lava ( )
      devolve ( )