AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79582354
Accepted
Stef1611
Stef1611
Asked: 2025-04-19 19:48:58 +0800 CST2025-04-19 19:48:58 +0800 CST 2025-04-19 19:48:58 +0800 CST

"%" em uma matriz de tipo derivado de Fortran cria uma cópia na memória?

  • 772

Gostaria de saber como "%" funciona em uma matriz de tipo derivado.

Eu escrevi o seguinte programa onde o operador "+" foi sobrecarregado:

module my_mod

  implicit none

  type :: my_type
    real :: r1 , r2
    integer :: i1, i2
  end type my_type
  
  interface operator(+)
    module procedure add_my_type_vec, add_my_type
  end interface
  
contains
  function add_my_type_vec(a,b) result(res)
    type(my_type), dimension(:),intent(in) :: a, b
    type(my_type), dimension(size(a)) :: res

      res%r1 = a%r1 + b%r1
      res%r2 = a%r2 + b%r2
      res%i1 = a%i1 + b%i1
      res%i2 = a%i2 + b%i2
      
  end function add_my_type_vec
  
  function add_my_type(a,b) result(res)
    type(my_type), intent(in) :: a, b
    type(my_type) :: res

      res%r1 = a%r1 + b%r1
      res%r2 = a%r2 + b%r2
      res%i1 = a%i1 + b%i1
      res%i2 = a%i2 + b%i2
      
  end function add_my_type
  
end module my_mod

program my_pgm
    use my_mod
    implicit none
    
    type(my_type),allocatable, dimension(:) :: my_vec1, my_vec2, my_vec3
    
    write(*,*) "Sum on type : ", my_type(1.0, 2.0, 1, 2) + my_type(1.0, 2.0, 1, 2)

    allocate(my_vec1(1000), my_vec2(1000), my_vec3(1000))
    my_vec1 = my_type(1.0, 2.0, 1, 2)
    my_vec2 = my_type(1.0, 2.0, 1, 2)
    my_vec3 = my_vec1 + my_vec2
    
    write(*,*) "Sum on vec of type : ", my_vec3(123)
    

end program my_pgm

Na add_my_type_vecfunção, como %funciona? Por exemplo, na instrução res%r1 = a%r1 + b%r1, há a criação (ou seja, cópia de memória) de dois arrays de reais que contêm apenas a%r1e b%r1, a soma é feita nesses arrays e, em seguida, a atribuição é feita em res%r1? Acho que é mais complicado.

fortran
  • 2 2 respostas
  • 96 Views

2 respostas

  • Voted
  1. Best Answer
    francescalus
    2025-04-19T21:18:14+08:002025-04-19T21:18:14+08:00

    Os compiladores geralmente são livres para criar matrizes temporárias sempre que quiserem. 1 Há momentos, como você verá em muitos posts aqui, em que cópias temporárias são efetivamente necessárias ou altamente desejáveis. Esta outra resposta , por exemplo, aborda alguns casos.

    Como exemplo prático, este é um caso em que o pensamento pode ser elaborado, em vez de uma resposta estrita ser dada.

    Em todo o código aqui, há muitas oportunidades para que um array temporário seja criado em torno de add_my_type_vec, como:

    • os argumentos fictícios da matriz ae bpodem ser copiados
    • as matrizes do lado direito das atribuições ( a%r1, b%r1, etc.) poderiam ser copiadas
    • a avaliação dos lados direitos ( a%r1+b%r1, etc.) poderia ir para um local temporário
    • o resultado da função pode ser uma variável armazenada temporariamente que depois é copiada para o lado esquerdo da atribuição do seu resultado.

    Nenhuma cópia de qualquer classe é necessária aqui, nem é particularmente benéfica.

    Os argumentos fictícios ae bassumem a forma, e o compilador sabe que eles são (simplesmente) contíguos.

    A matriz a%r1(etc.) não é contígua, mas tem um passo constante: um compilador pode facilmente lidar com o passo a passo entre os elementos.

    O lado esquerdo de res%r1 = a%r1 + b%r1não aparece de forma alguma (especialmente de forma complicada) no lado direito: a avaliação do lado direito não afeta o lado esquerdo, portanto, nenhuma cópia é necessária para manter a avaliação antes da atribuição.

    Da mesma forma, com a atribuição do resultado da função, não há interações entre nenhuma das variáveis ​​envolvidas.

    Não há necessidade de contornar as demandas de finalização em lugar nenhum.

    Basicamente, tudo o que o compilador precisa fazer é iterar sobre os elementos de my_vec3e atribuir diretamente a soma em pares dos elementos de my_vec1e my_vec2, percorrendo essas matrizes de maneiras bem chatas.

    Um compilador poderia decidir fazer qualquer uma das cópias se achasse sensato ou se quisesse jogar com mais segurança. Normalmente, você pode pedir a um compilador para lhe informar (em tempo de compilação ou execução) quando estiver fazendo uma cópia ou se estiver implementando o mecanismo necessário para permitir uma decisão de cópia.

    O único motivo para se preocupar com os componentes (uso de %) é que os arrays referenciados não são contíguos. Fortran é muito capaz de lidar com arrays não contíguos sem exigir cópias. Restrições a arrays "complicados" e usos "complicados" de componentes existem para tornar o tratamento desses casos comuns realmente muito chato (para compiladores).


    1 Um compilador é necessário para garantir que os efeitos em um temporário sejam efeitos em uma entidade associada a esse temporário. Por exemplo, se houver uma cópia temporária de um argumento fictício, o argumento real deve refletir quaisquer alterações (apropriadas). As regras do Fortran sobre aliasing são restrições em programas que facilitam muito a tarefa do compilador de determinar quando os efeitos precisam ser visíveis em técnicas como copy-in/copy-out.

    • 4
  2. PierU
    2025-04-19T21:25:36+08:002025-04-19T21:25:36+08:00

    Em operações de array res(:)%r1 = a(:)%r1 + b(:)%r1como as de add_my_type_vec(), espero que qualquer compilador otimizador decente NÃO crie arrays temporários.

    Ainda assim, essa abordagem provavelmente não é a ideal em termos de acesso à memória: a(:)%r1é um array não contíguo com um stride de 4 (porque você tem 4 unidades de armazenamento numérico em seu tipo derivado), e instruções vetoriais, pelo que sei, são menos eficientes em arrays com strides. Além disso, ao executar sequencialmente as 4 operações de array, apenas 25% do conteúdo de uma linha de cache é usado antes que a linha de cache seja apagada e recarregada posteriormente.

    Por outro lado, somando elemento por elemento (do tipo derivado array), os caches são melhor aproveitados, mas não há como aproveitar as instruções do vetor.

    No final, somente um benchmark pode dizer qual é a abordagem mais eficiente... para a combinação de máquina/compilador que você está usando.

    Observe que você não precisa escrever duas rotinas separadas aqui. Você pode escrever uma única elementalrotina que lidará com as adições escalares e de array (o que o compilador fará nos bastidores não é óbvio, no entanto).

    module my_mod
    
      implicit none
    
      type :: my_type
        real :: r1 , r2
        integer :: i1, i2
      end type my_type
      
      interface operator(+)
        module procedure add_my_type
      end interface
      
    contains
      
      elemental function add_my_type(a,b) result(res)
        type(my_type), intent(in) :: a, b
        type(my_type) :: res
    
          res%r1 = a%r1 + b%r1
          res%r2 = a%r2 + b%r2
          res%i1 = a%i1 + b%i1
          res%i2 = a%i2 + b%i2
          
      end function add_my_type
      
    end module my_mod
    
    program my_pgm
        use my_mod
        implicit none
        
        type(my_type),allocatable, dimension(:) :: my_vec1, my_vec2, my_vec3
        
        write(*,*) "Sum on type : ", my_type(1.0, 2.0, 1, 2) + my_type(1.0, 2.0, 1, 2)
    
        allocate(my_vec1(1000), my_vec2(1000), my_vec3(1000))
        my_vec1 = my_type(1.0, 2.0, 1, 2)
        my_vec2 = my_type(1.0, 2.0, 1, 2)
        my_vec3 = my_vec1 + my_vec2
        
        write(*,*) "Sum on vec of type : ", my_vec3(123)
        
    
    end program my_pgm
    
    • 3

relate perguntas

  • Erro waitall 6MPI "A solicitação fornecida no elemento 0 da matriz era inválida (tipo=0)"

  • Operações elemento a elemento em matrizes de objetos de tipo derivado com operadores sobrecarregados

  • Alterar membros de dados de tipo derivado em `SUBROUTINE` é permitido mesmo com INTENT(IN). Como proteger dados?

  • armazenando um ponteiro de procedimento dentro de um tipo em Fortran

  • Continuação de linha seguida de linha em branco em Fortran

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve