Skip to content

← Dtypes and Numerics step 1 of 6

Medium Primitives

What dtype comes out

Jump to the task

The dtype produced by addition depends on the operand dtypes and on whether an operand is a Python number, a scalar tensor or a tensor with dimensions. Use the actual operands to check the result when precision matters.

Two tensors with dimensions

For the dtypes in this exercise, familiar examples include:

int32   + float32 -> float32
float16 + float32 -> float32
bool    + int8    -> int8
int16   + int64   -> int64

Promotion considers categories in the order boolean, integer, floating point, complex. It also considers which dtype can represent the operands' types within a category. “The wider one wins” is only a shortcut: float16 and bfloat16 have the same width but promote together to float32. Promotion does not inspect the actual values to guarantee exact results. For example, float32 cannot represent every int32 value exactly.

Python numbers and scalar tensors

These examples assume PyTorch's default floating dtype is float32:

import torch

x = torch.ones(2, dtype=torch.float16)
print((x + 1.5).dtype)                 # torch.float16
print((x + torch.tensor(1.5)).dtype)   # torch.float16
print((x + torch.tensor([1.5])).dtype) # torch.float32

A Python float does not widen this floating tensor just because Python's float uses double precision. A zero-dimensional floating tensor also does not force its precision onto a tensor with dimensions in the same category. The one-dimensional float32 operand in the last line does widen the result.

Categories still matter. Adding a Python float to an integer tensor gives a floating result, using the default floating dtype. A scalar tensor's own dtype can matter when it introduces a higher category, so scalar tensors and Python numbers are not interchangeable in every promotion case.

Changing the default dtype changes examples that rely on it. If an operation needs a specific precision, specify it explicitly and check the result's dtype instead of assuming promotion preserves every value.

Your task

def result_dtype(a_dtype: str, b_dtype: str) -> str

Each argument names a dtype, except "pyfloat" means the Python number 1.5 and "pyint" means the Python integer 2. For a dtype name, construct torch.ones(2, dtype=getattr(torch, name)).

At least one operand is a tensor. Add the operands and return the result's dtype name without the torch. prefix. The tests use the default float32 floating dtype. Keep Python-number operands as numbers rather than wrapping them in one-dimensional tensors.