Portable remainder kernel: wrong sign for integers and float64 rounded to float

Fechada Para iniciantes
#23,682 0 comentários 0 reações 2 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

@JakeStevens já está trabalhando nisso.

Desde 12/10/2026.

  • #23683 de @usmanmateen — aberto

Avaliação

Dificuldade
2/5
Tempo estimado
1-3 horas
Facilidade para iniciantes
82/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
cpp, python, pytorch

Direção de pesquisa

Leia kernels/portable/cpu/util/math_util.h e o op_remainder_test.cpp existente. Confira as sobrecargas de inteiros e de ponto flutuante com base nos casos de sinal e precisão da issue, incluindo a forma escalar. O trabalho estará concluído quando os testes cobrirem esses casos e os kernels portáveis corresponderem aos resultados do PyTorch.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

bug module: kernels triaged
🐛 Describe the bug

The portable remainder kernels give results that differ from PyTorch in two cases.

  1. Integers with mixed signs. ATen's remainder takes the sign of the divisor (-7 % 3 == 2), but for integer types utils::remainder_override in kernels/portable/cpu/util/math_util.h returns a % b, which takes the sign of the dividend (-1). The floating-point overload already adds b in this case, as the comment above both overloads describes. The integer one doesn't.
  2. float64 loses precision. The floating-point overload stores std::fmod(a, b) in a float, so double results are rounded to float precision.
import torch
from executorch.exir import to_edge
from executorch.runtime import Runtime


class Rem(torch.nn.Module):
    def forward(self, a, b):
        return torch.remainder(a, b)


def run(a, b):
    prog = to_edge(torch.export.export(Rem(), (a, b))).to_executorch()
    return Runtime.get().load_program(prog.buffer).load_method("forward").execute([a, b])[0]


a = torch.tensor([7, -7, 7, -7])
b = torch.tensor([3, 3, -3, -3])
print(torch.remainder(a, b).tolist(), run(a, b).tolist())
# [1, 2, -2, -1] [1, -1, 1, -1]

a = torch.tensor([123456789.123456789], dtype=torch.float64)
b = torch.tensor([1000.0], dtype=torch.float64)
print(torch.remainder(a, b).item(), run(a, b).item())
# 789.1234567910433 789.1234741210938

The integer case affects int8, int32 and int64, and remainder.Scalar too: torch.remainder(x, 3) gives -1 for x = -1 instead of 2. With the XNNPACK partitioner the result is the same, since these ops run on the portable kernel. A model that uses Python's % on integer tensors (for example to wrap positions or bucket ids) gets different values after export.

The existing op_remainder_test.cpp only covers 46 % 4. I have a fix with tests and will open a PR.

Versions

executorch 1.5.1 (math_util.h is the same on main at f2575be), torch 2.14.1+cpu, Python 3.12, Linux x86_64 (WSL2).

cc @larryliu0820 @manuelcandales @JakeStevens

Linguagem predominante
Python
Estrelas
5.1k
Forks
1.2k
Merge médio
1d 18h
PRs com merge (30d)
668

Preparar o ambiente

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de pytorch/executorch

Todas as issues de pytorch/executorch

Issues semelhantes

Mais issues de Python

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.